😅

Rustで『安全』と言い切れるか?Cloudflare 障害と unwrap() のリアル

に公開

はじめに

2025年11月18日、インターネットインフラ大手 Cloudflare にて、世界規模のサービス障害が発生しました。
その原因として、Rust 製プロキシサービス内で起きた panic の一撃が引き金になったことが報じられています。中でも注目されたのが、Rust 標準ライブラリの Option::unwrap() または Result::unwrap() の呼び出しです。
しかし、この「unwrap が原因」という一言だけで終わる話ではありません。今回は、Rust における unwrap() の意味・使いどころ・今回の障害が教えてくれたことを丁寧に振り返ります。


Rust における unwrap() とは

まず、Rust 標準ライブラリにおける Option<T> および Result<T, E> 型からおさらいしましょう。

Option/Result 型

Rust では、値が存在しない可能性やエラーの可能性を型として表現します。

  • Option<T>Some(T) または None の二択。
  • Result<T, E>Ok(T) または Err(E) の二択です。
    Rust の設計思想では、「ヌルポインタ」や「例外(Exceptions)」に頼るのではなく、処理可能な値として可能性を明示することが推奨されています。

unwrap() の振る舞い

Option<T>Result<T, E>.unwrap() を使うと以下のようになります:

let maybe_value: Option<&str> = Some("foo");
let value = maybe_value.unwrap(); // "foo"

let none_value: Option<&str> = None;
let value2 = none_value.unwrap(); // panic: “called `Option::unwrap()` on a `None` value”

また Result<T, E>::unwrap() は Ok(v) なら v を返し、Err(e) の場合には panic(実行中止)となります。

つまり、unwrap() は “この値は必ずある/この処理は必ず成功する” という前提のもとで使われる関数です。もしその前提が崩れた場合、プログラムは即時に終了(panic)します。

Rust の公式サイトも unwrap() による panic の可能性を明記しており、慎重に使うよう警告しています。 

Cloudflare の障害と unwrap() の関係性

ここからは、Cloudflare における障害と unwrap() がどのように関係していたのかを整理します。

障害の概要

  • 2025年11月18日、Cloudflare の Bot Management 機能で「特徴量ファイル(feature file)」のレコード数が想定値を超えて急増。仕様では数十レコード想定だったところ、200〜300超に。
  • 結果として、該当プロキシサービスが Rust 製であったため、内部処理で想定外のデータを扱った際に panic が発生。
  • 当該サービスは世界中のエッジノードに展開されていたため、影響が一気に波及しました。
    (参考記事) 

なぜ “unwrap が原因” と言われたのか

報道および技術ブログでは以下の論点が挙げられています

  • Cloudflare の障害を “a single Rust .unwrap() in Cloudflare’s edge network” と表現した記事もあります。 
  • もう一方では「unwrap そのものが悪ではなく、unwrap が前提としていた “必ずある” を保証できない状況だった」という議論もあります。

なぜ致命的な影響に至ったのか

複数の要因が重なりました

  1. 前提条件の破壊
    仕様上「特徴量ファイルは数十レコード」という前提が、実際には数百レコードという異常値となっており、その変化を検知できていませんでした。
  2. 入力検証・防御コードの欠如
    異常な入力を事前に弾く、またはフォールバックする処理が不十分だったという指摘があります。
  3. unwrap による panic によってプロキシ停止
    外部入力に対して unwrap が呼ばれた時点で panic すると、そのノードが停止。多数ノード停止に繋がりました。
  4. 分散システムという特殊環境
    エッジネットワークで大量ノードが同一処理をしており、一部の panic がサービス全体に影響。

まとめると、「unwrap を使ったからバグが起きた」という単純な話ではなく、むしろ「unwrap によって前提が崩れた時の保証・防御がなかった」ことが本質です。

開発者が気をつけるべき unwrap() の使い方

ここからは、実務的な観点で Rust 開発者として unwrap() をどう扱うべきかを整理します。

✅ 安全に unwrap() を使って良い場面

  • プログラムの 初期化段階など、「ここで読み込む値は必ず存在する」という設計が明確な場合。
  • テストコードやスクリプト用途で、むしろ panic を発生させて異常を可視化したいとき。
  • 性能クリティカルなパスで、「失敗なし/処理速度を優先」という判断をした場面。

ただし、これらの場合でも「なぜ失敗しないのか」をコード・コメント・レビューで明示しておくことが望ましいです。

❌ unwrap() を控えるべき場面

  • 本番環境、特に 外部入力/ユーザー入力/ネットワーク/I/O が絡む処理。
  • ミッションクリティカルなサービス、分散環境、停止がシステム全体に影響を与える状況。
  • 入力仕様が将来変化/拡張可能性がある箇所。

Rust の unwrap() は「安全な前提のもとで選ばれるべき」ものであり、誤用すれば panic によるサービス停止リスクを抱えます。

今回の不具合から学ぶべき設計・運用改善

Cloudflare の事例から、実践的にどのような改善策が考えられるか見ていきます。

🔍 得られる主な教訓

  • 前提条件を壊れないものと断定しない
    仕様が将来変わる/想定外データが来得ることを前提に設計すべきです。
  • 入力/データ構造の拡張・異常値対応を必ず検討する
    想定レコード数を超えたケースをどう扱うか事前に策を講じておくこと。
  • panic を前提としないサービス設計
    Rust でも panic が致命的になり得ます。分散環境では「エラーを局所化」「停止しない仕組み」が重要。
  • 監視・アラート・フォールバックの体制整備
    panic が起きても即時気づき、フェイルオーバー可能な設計を用意しておくこと。
  • レビュー・テスト・コメントによる自己ドキュメント化
    unwrap を使った箇所には「なぜこれは失敗しないのか」をレビューで問う習慣を。

✅ 改善すべきコード設計例

// 悪い例(unwrap 使用)
let features = parse_feature_file(path).unwrap();

// 良い例(明示的エラーハンドリング+異常データチェック)
let features = parse_feature_file(path)
    .map_err(|e| {
        log::error!("feature_file parse failed: {:?}", e);
        e
    })?;
if features.len() > MAX_FEATURES {
    log::warn!("feature file too large: {} entries", features.len());
    // フォールバック処理へ
}

さらに、panic の回避設計・監視への連携も視野に入れるべきです。

unwrap() を使うべき/控えるべき基準のチェックリスト

以下に、開発時にチェックできる簡易リストを示します

項目 評価
この値/この処理は 必ず成功する と設計段階で明文化できているか
仕様変更・入力の拡張により前提が壊れる可能性を検討済みか
入力検証・サイズチェック・フォールバックが実装されているか
panic がシステム全体停止につながる構成ではないか
unwrap 使用箇所にコードコメント・レビューが付されているか

うちどれか多く「×」が入るなら、unwrap() ではなくエラー処理を選択すべきと言えます。

まとめ

  • Rust の unwrap() は便利な反面、「値が必ずある」と前提することで panic に直結する強力な構文です。
  • Cloudflare の障害事例では、Rust 製サービス内での unwrap() が “きっかけ”となり、サービス停止という形で現れましたが、真の原因は「前提の壊れうる性」と「防御設計の欠如」にあります。
  • 開発者としては、unwrap() を使うかどうかを設計段階で吟味し、使うならその前提を保証できる構成にしておくこと、使わないなら明示的なエラー処理を実装しておくことが鍵です。
  • 本番環境では、特にネットワーク・I/O・分散環境では「失敗しても止まらない/止まっても即復旧できる」設計が欠かせません。

本記事が、Rust を用いた実践的なシステム開発において、unwrap() の使いどころを見極めるための一助となれば幸いです!

Discussion