メインコンテンツへスキップ
Dev Tools 37分で読める

Claude APIの拒否はHTTP 200|stop_reason refusalとfallbacks実践ガイド

Claude APIが返す stop_reason: "refusal" は、エラーではなくHTTP 200として返る。だから監視に映らない。

Djangoの暗号資産トレーディングボットを書いていた開発者が、ある日セッションを勝手に別モデルへ切り替えられた。攻撃コードもマルウェアも、生物学の話も一切書いていない。資格情報の暗号化、ログイン権限の管理、操作履歴の記録、危険な実行ファイルを弾く保管機能。どれもWebサービスなら当然入っている機能だ。

本人の分析はこうだ。「トリガーになったのはおそらく、プロジェクトのコンテキストとClaude Code自身が注入する環境情報に含まれる、無害だがセキュリティ隣接の語彙だ。私のリクエストの中ではない」(claude-code Issue #67132, 2026年6月10日)。

2026年7月24日、Anthropicはこの「拒否されたら別モデルに回す」処理を、リクエスト1行で済ませられるベータを公開した。公式リリースノートの記載はこうだ。「The fallbacks parameter now supports a "default" mode, which applies Anthropic’s recommended fallback models by refusal category.」(Claude Platform release notes)。

この記事はこんな人におすすめ
  • Claude API上でエージェントを本番運用していて、原因不明の品質低下や請求のズレに悩んでいる開発者
  • Claude Fable 5 / Claude Opus 5を使いたいが、安全性分類器の誤検知が怖くて踏み切れない人
  • セキュリティ監査やライフサイエンス系の業務でClaudeを回しているチーム
先に結論
  1. 分類器の拒否はエラーではなく HTTP 200 で返ります。エラー率や5xxだけを見ている監視では検知できません。まずここを直してください。
  2. fallbacks: "default" は自前のモデルリスト管理を不要にします。Claude APIのみを使う新規実装なら、まず検討したい選択肢です。
  3. ただしClaude API限定です。Bedrock / Google Cloud / Microsoft Foundry、そしてバッチAPIでは使えません。
  4. サブエージェントの呼び出しには継承されません。 ツール実行の内側から出るモデル呼び出しには、個別にフォールバックを設定する必要があります(サブエージェント=AIが自分の作業のために内部で呼び出す別のAI。親の設定が引き継がれないため、設定漏れが起きやすい箇所です)。

実装しない立場の方向けに要点を3行でまとめると、こうなる。AIが仕事を断ったのに、システム上は「成功」として記録されるため障害として検知できない。断られた分は性能の低いモデルに回されるので、品質と請求額の両方がズレる。対策の設定自体は1行だが、その前に発生件数を1〜2週間計測するほうが先だ。

拒否はエラーとして返ってこない

安全性分類器とは、Anthropicがモデルの手前に置いている自動チェック機構だ。送られてきたリクエストの内容を見て、サイバー攻撃や生物兵器などの危険な領域に該当すると判定すると、モデルに処理させずリクエストを断る。人間の審査ではなく機械判定なので、無害な業務が引っかかることもある。この仕組みが導入された経緯はClaude Fable 5の48時間混乱全記録にまとめた。

Claude Fable 5とClaude Opus 5には、この分類器が載っている。作動したとき、APIは例外を投げない。通常のHTTP 200レスポンスとして、stop_reason: "refusal" を返す。

{
  "model": "claude-fable-5",
  "content": [],
  "stop_reason": "refusal",
  "stop_details": {
    "type": "refusal",
    "category": "cyber",
    "explanation": "This request was declined because it could enable cyber harm."
  },
  "usage": { "input_tokens": 412, "output_tokens": 0 }
}

この設計が実運用でどう効くかは、公式ドキュメントの落とし穴リストに率直に書かれている。「A refusal is an HTTP 200, so monitoring built on error rates or 5xx responses never sees it.」(Refusals and fallback)。DatadogでもSentryでも、5xxとタイムアウトだけ見ている限り、この事象はダッシュボードに現れない。夜間バッチが静かに空の応答を返し続けても、グラフは緑のままだ。

category は5種類ある。

category意味誤検知しやすい業務
cyberマルウェアやエクスプロイト開発を助長しうる防御側のセキュリティ監査、暗号実装、認証周り
bio生物学的な危害を助長しうる医療画像、ゲノム解析、創薬
frontier_llm競合AIモデルの開発を支援しうる(商用利用規約で制限)通常の機械学習ワークフロー
reasoning_extraction内部の推論過程を本文として出力させようとしている「理由を説明して」系のプロンプト
general_harms有害と判定された領域に関連しうる判定範囲が広く、推測が難しい

実装上の注意が2つある。categoryexplanationどちらも null になりうる。分類器が名前付きカテゴリに紐づかない拒否を返したときの、正常かつ恒久的な値だ。そして explanation の文面は安定しない。公式ドキュメントは「display it rather than parse it」と明記している。分岐は stop_reasonstop_details.type で書く。文面の安定性が保証されていないため、正規表現で拾う実装は将来動かなくなる恐れがある。

誤検知は「起きうる」ではなく起きている: cyber・bioで刺さる実例

Anthropicはガードレールを保守的に調整した結果として「無害なリクエストを拾ってしまうこともある」と認めつつ、分類器が作動するのは平均で全セッションの5%未満だとしている(The Register, 2026年6月10日)。この数字自体は低い。

ただし注意したいのは、これが「分類器が作動する率」であって「フォールバックが成功した率」ではない点だ。APIのフォールバックはオプトインなので、設定していなければ5%未満の拒否はそのまま失敗として返る。そして、5%未満が誰に当たるかは均等とは限らない。カテゴリ別の内訳は公表されていないが、本記事で確認できた公開報告は、セキュリティ監査とライフサイエンス隣接の領域に偏っていた。以下はあくまでその傾向にすぎない。

自社コードの監査で刺さったケース。 マルチテナントのASP.NET Coreサービスに対して、リリース前のセキュリティ監査を6並列の読み取り専用エージェントで走らせた開発者は、途中でこう表示された。「Fable 5’s safety measures flagged this message for cybersecurity or biology topics… Switched to Opus 4.8」(claude-code Issue #66697, 2026年6月9日)。自分のコードを自分で監査する、権限も正当性も明白な作業だ。

ここは光の側も書いておきたい。切り替わった後の監査は、GitHubに誤ってpushされていた生きた資格情報1件をCRITICALとして検出し、XSSのシンク2件も見つけている。開発者はキーをローテートし、3テナント全部に修正を投入した。フォールバック自体は仕事を止めなかった。 止まったのは、より強いモデルで監査を受ける選択肢だ。

逆に、フォールバックが効かなかったケース。 メインをOpus 4.8、レビュー担当のアドバイザーをFable 5に置く構成で走らせていた開発者は、分類器が作動した瞬間に「The advisor tool is unavailable. Do not try to use it again.」というだけのエラーを受け取った。フォールバックは走らず、アドバイザーはセッション終了まで無効化された。本人の指摘が鋭い。「アドバイザーが無効になるのは、より強いレビュアーが最も価値を持つ領域(セキュリティ監査、生物学隣接のコード)でちょうど起きる」(claude-code Issue #67306, 2026年6月11日)。

なぜフォールバックが走らなかったのか。AIが道具として別のAIを呼ぶとき、その呼び出しは親の設定を引き継がない。公式ドキュメントの落とし穴リストに明記されている。「Give sub-agent calls their own fallback. The fallbacks parameter does not propagate into model calls made from inside tool execution.」(Refusals and fallback、2026年7月26日閲覧)。つまりツール実行の内側から出るモデル呼び出しには、親リクエストのフォールバック設定が届かない。アドバイザー機能の仕組みはClaudeのアドバイザーツールとコスト最適化でも扱ったが、この非継承は自作エージェントでも同じ形で踏む。

日本語圏の報告も傾向は同じだ。 X・Redditの投稿を整理したzephel01氏のまとめには、医療画像や神経科学の研究に加えて「pulled porkのショッピングリスト」まで誤検知したという投稿が紹介されている(いずれも個々のユーザー投稿の紹介であり、当サイトで再現確認はしていない)。回避策として挙がっているのは、プロンプトから「思考過程を出力せよ」を外す、システムプロンプトで業務コンテキストを明示する、Qwenやローカルモデルとのハイブリッド構成にする、といった実務的なものだ(note, 2026年6月10日)。

6月のリリース直後には hello と打っただけでフォールバックが発生した報告もあった。その48時間の混乱と、Anthropicが「無通知の劣化」を「可視化されたフォールバック」に改めるまでの経緯はClaude Fable 5の48時間混乱全記録にまとめている。

fallbacks: “default” が何を変えたか: 実装と挙動

7月24日のベータで変わったのは、フォールバック先モデルのリストを自分で保守しなくてよくなった点だ。

response = client.beta.messages.create(
    model="claude-fable-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "..."}],
    fallbacks="default",
    betas=["server-side-fallback-2026-07-01"],
)
print(response.model)  # 実際に答えたモデルが入る

導入時に確認すべき点を先にまとめる。この5つを外すと、設定したつもりで効いていない状態になる。

  1. ベータヘッダーは server-side-fallback-2026-07-01 固定。他の値では400エラーになる
  2. fallbacks="default" を指定する(自分でモデルを選ぶ場合は最大3件のリスト)
  3. リトライハンドラ、エラー復旧の分岐、バックグラウンドワーカーの 全経路 に付ける
  4. ツール実行の内側から出るモデル呼び出しには 個別に 設定する
  5. コスト集計とアラートを usage.iterations に接続する

"default" を指定すると、APIは拒否カテゴリごとにAnthropicが推奨するモデルを選んで再実行する。Anthropicはモデル単位・ポリシーカテゴリ単位で安全策を設定しており、カテゴリによっては能力の低いモデルへ落とすか、そもそも拒否を維持する。推奨先が存在しないカテゴリでは拒否がそのまま返る。

自分でモデルを指定したい場合は、"default" の代わりに最大3件のモデルリストを渡す。品質検証済みのモデルに固定したいときはこちらだ。Claude Fable 5の許可されたフォールバック先は、公式には Claude Opus 4.8 と Claude Opus 5 の2つ(Fallback credit)。Opus 5の仕様はClaude Opus 5完全ガイドで整理した。

どのモデルが答えたかは2箇所で分かる。トップレベルの model フィールドと、content の先頭に入る fallback ブロックだ。

{
  "model": "claude-opus-4-8",
  "content": [
    { "type": "fallback",
      "from": { "model": "claude-fable-5" },
      "to": { "model": "claude-opus-4-8" } },
    { "type": "text", "text": "..." }
  ],
  "usage": {
    "iterations": [
      { "type": "message", "model": "claude-fable-5", "output_tokens": 0 },
      { "type": "fallback_message", "model": "claude-opus-4-8", "output_tokens": 264 }
    ]
  }
}

監視で見るべきなのは usage.iterations という項目だ。ここに試行ごとの記録が並ぶ。拒否したモデルは通常の message エントリ、実際に答えたモデルは fallback_message エントリとして入る。

集計コードはこの程度で足りる。拒否とフォールバック成功を別イベントとして出し、モデル別にトークンを積む。

served_by_fallback = any(
    it.type == "fallback_message" for it in (response.usage.iterations or [])
)

if response.stop_reason == "refusal":
    # 分類器が拒否し、フォールバックも成立しなかった。ここが静かな失敗
    emit("claude.refusal", category=response.stop_details.category)
elif served_by_fallback:
    emit("claude.fallback_served", model=response.model)

# 請求額はモデルごとに積む。トップレベルのusageだけでは足りない
for it in (response.usage.iterations or []):
    add_cost(model=it.model, in_tok=it.input_tokens, out_tok=it.output_tokens)

そして地味に重要なのが スティッキールーティング だ。一度フォールバックした会話について、APIはどのモデルが応答したかを記録する。以降その会話で fallbacks を含むリクエストは、拒否されるとわかっている元モデルを試さず、直接フォールバック先へ行く。保持期間は約1時間、組織スコープ、会話プレフィックスのコンテンツハッシュで管理される。メッセージ本文そのものは保存されない。

ただしベストエフォートなので、元モデルが再試行されるケースは常に想定しておく。実装側では「毎ターン元モデルが答えるかもしれない」前提で response.model を読んで記録する。スティッキーが効くことを前提にした分岐は書かない。

拒否とフォールバックの課金・レート制限の落とし穴

課金の原則はシンプルだ。実際に応答したモデルの料金を払う。 出力前に拒否した試行は課金されない。トークン数は usage.iterations のエントリに出るが請求対象外だ。

ここで料金差が効いてくる。Claude Fable 5はリスト価格で入力100万トークンあたり10米ドル・出力50米ドル。Opus 4.8とOpus 5はどちらも入力5米ドル・出力25米ドルだ(いずれも税別・2026年7月26日時点の公式料金ページに基づく)。つまりフォールバックが発生した場合、応答単価はリスト価格ベースで概ね半分程度になる計算だ(プロンプトキャッシュやフォールバッククレジットの適用状況によって実際の請求額は変動する)。

ただしこれは値引きではない。10米ドルの性能を期待して払っていたところに、5米ドルのモデルが答えている状態だ。安くなったのではなく、買ったものが変わっている。

この差を踏み抜いた報告がある。サードパーティのAIインターフェースomp(oh-my-pi)のリポジトリには、7月1日の再デプロイ以降Fable 5からOpus 4.8への切り替えが起きているのに、レスポンス内のフォールバック指標が参照されていないという報告が投稿された。記述はこうだ。「the served model is discarded. A turn Opus 4.8 wrote is labeled claude-fable-5 everywhere.」報告者は、統計上のコストが「exactly 2× overstated」になっていたと述べている(oh-my-pi Issue #4177, 2026年7月1日。本記事執筆時点の報告内容であり、その後修正されている可能性がある。実装の現状は最新のリポジトリで確認してほしい)。実際より2倍高く見えるだけなら害は小さいが、逆向きの実装をすれば請求額を過小に見積もる。自分のコスト集計コードが usage.iterations を見ているか、一度確認する価値はある。

レート制限にはもっと厄介な性質がある。課金は発生しなくても、拒否された試行はレート制限を消費する。そして試行はそれぞれ自分のモデルのレート制限を消費するため、フォールバック先が制限超過か過負荷状態だと、フォールバック試行そのものが行われず、直前の拒否がそのまま返る。公式ドキュメントの警告は直球だ。「Size the fallback model’s rate limits for the refusal volume you expect, or fallbacks degrade to refusals under load.」(Refusals and fallback、2026年7月26日閲覧)。

つまりフォールバックは、いちばん必要な高負荷時にこそ機能しなくなりうる。このときは stop_details.recommended_model に直接リトライすべきモデル名が入るが、これはヒントであって保証ではなく、null のこともある。

なお、フォールバックを起こすのは分類器の拒否だけだ。レート制限、過負荷、サーバーエラーはそのまま返る。529エラー側の耐障害設計は別問題で、そちらはClaude Codeのフォールバックモデル設定で扱っている。

フォールバック実装3方式の選び方: API・SDK・手動リトライ

公式ドキュメントは3方式を提示している。

状況方式理由
Claude API、最小構成で済ませたいサーバーサイドフォールバック1リクエスト1レスポンス。リトライはAPI側
Bedrock / Google Cloud / Foundry、SDK利用SDKミドルウェアクライアントに1度設定すれば自動リトライ
生HTTPや独自リトライ手動リトライ + フォールバッククレジット完全な制御。クレジットでコストを抑える

サーバーサイドフォールバックとSDKミドルウェアは、フォールバッククレジットを自動で適用してくれる。手動実装だけがクレジットを意識する必要がある。

フォールバッククレジットは、モデルを切り替えたことで発生する無駄な追加料金を打ち消す仕組みだ。プロンプトキャッシュがモデル単位である事実への対処にあたる。Fable 5用に温まったキャッシュは、Opus 4.8で再実行するとき使えない。書き込みは読み出しより高いので、素朴なリトライは差額を丸ごと払う。拒否レスポンスの stop_details.fallback_credit_token をリトライに載せると、最初からそのモデルで会話していたかのように課金される。有効期限は 拒否から5分 で、system / messages / tools などプロンプトを形づくるフィールドは完全一致が必要だ。

使えない場所も明確にしておきたい。fallbacks パラメータは Message Batches API で非対応(含めるとそのアイテムがエラー結果になる)、Amazon Bedrock・Google Cloud・Microsoft Foundry では利用不可。バッチの拒否はクレジットトークンも発行されない。バッチで拒否が出たら、該当アイテムを集めてフォールバックモデルで再投入する運用を組む。

fallbacks: “default” を使う前の4つの注意点

ベータであること。 ヘッダーには 2026-07-01 という日付が入る。ドキュメントには、この日付以外の server-side-fallback-* 値では fallbacks が400エラーで弾かれるとある。2026-06-01 は明示リスト形式のみ受け付ける。以前のプレビューに合わせて実装していたなら、ヘッダーとリクエスト・レスポンス形状をまとめて更新する必要がある。

品質は下がる可能性がある。 フォールバックは「拒否されない」ことを保証するだけで、「同じ品質で答える」ことは保証しない。Fable 5のベンチマークを見て採用を決めたなら、実際に応答しているのがOpus 4.8である割合を知らないまま運用していることになる。数字はClaude Fable 5公開レビューで比較した。

非ストリーミングでは部分出力が捨てられる。 ストリーミング中に途中で拒否された場合、フォールバックモデルは部分出力から続きを書く。非ストリーミングでは部分出力を破棄して最初から書き直す。拒否された試行の出力トークンは usage.iterations に残る。同じ処理でも呼び出し方によって挙動が変わるため、途中拒否のコストを抑えたいならストリーミングを選ぶ。部分出力が引き継がれるぶん、再生成が減る。

設定漏れはいちばん危ない経路で起きる。 ドキュメントは「Configure fallback on every request path」と念を押している(Refusals and fallback、2026年7月26日閲覧)。リトライハンドラ、エラー復旧の分岐、バックグラウンドワーカー。フォールバックなしで再発行するハンドラは、まさに保護が必要なリクエストで保護を失う。グローバルなフラグや共有設定で管理するのも推奨されていない。リクエストのプロパティとして持たせるべきだ。

自分(電脳狐影)ならこうする

PMとしてAPIコストと運用リスクを見る立場からの判断を書く。分類器の内部実装まで踏み込める人間ではないので、あくまで使う側の設計の話だ。

最初にやるのは監視、フォールバック設定ではない。 fallbacks を入れる前に、拒否イベントの計測を仕込む。拒否1件で1イベント、fallback_message エントリ付きの応答で1イベント。この2つの差分が「拒否されたまま放置された件数」になる。1〜2週間データを取れば、そもそも自分のワークロードで分類器が刺さるのかが分かる。刺さっていないなら、この機能は不要だ。

採用するなら "default" から始める。 明示リストは、自分でモデル選定の責任を持つ形になる。推奨先はAnthropic側で更新されていくのだから、特別な理由がない限り委ねたほうが保守が減る。品質検証を通したモデルに固定する要件が出てきた段階で明示リストに移る。

サブエージェント経路を洗い出す。 ここが実務でいちばん効く。ツール実行の内側からモデルを呼んでいる箇所を全部リストアップし、それぞれにフォールバックを設定する。Issue #67306のアドバイザー無効化は、この非継承がユーザー体験としてどう見えるかの実例だ。自作エージェントを組んでいる人はClaude Agent SDK完全ガイドの構成図と照らして確認するといい。

セキュリティ・ライフサイエンス業務なら、自分はFable 5を第一候補には置かない。 これは公開報告から読み取れる傾向に基づく運用方針で、Anthropicがカテゴリ別の誤検知率を公表しているわけではない。誤検知の報告が偏っている領域で最高性能モデルを使う設計は、フォールバックを整えても不確実性が残る。Opus 5を主モデルに置き、必要な場面だけFable 5を試す構成のほうが運用が読める。過剰な拒否がコストに跳ね返る話はClaude Sonnet 5の拒否とコスト罠でも検証した。

コスト集計コードを直す。 ompで報告された2倍過大計上のケースは他人事ではない。トップレベルの usage は「返されたメッセージを生成した試行」の数字しか持たない。異なるモデルのトークンが1つのフィールドに合算されることはない。集計は usage.iterations を回すのが正しい。

次のステップ

フォールバックの設定より先に計測をおすすめします。まず1週間分のAPIレスポンスから stop_reason が refusal のリクエスト数と、usage.iterations に fallback_message を含む応答数を集計してください。両者の差が、いま静かに失敗している件数です。そのうえで、ツール実行の内側からモデルを呼んでいる箇所に個別設定を入れてください。

サブエージェント構成を確認する

関連記事


免責事項: 本記事のAPI仕様および料金は2026年7月26日時点の公開情報に基づきます。サーバーサイドフォールバックおよびフォールバッククレジットはベータ機能であり、仕様・提供条件・対応モデル・ベータヘッダーの値は予告なく変更される可能性があります。記載の料金は米ドル建て・税別のリスト価格であり、実際の請求は各プロバイダの最新ドキュメントとご自身の利用ログでご確認ください。フォールバックの発動率や誤検知の傾向は利用内容によって大きく異なり、本記事で引用した個別事例は再現性を保証するものではありません。本記事で引用したGitHub Issueおよび個人ブログの記述は、いずれも各投稿者による申立てや見解であり、当サイトがその内容を事実として検証・認定したものではありません。言及した製品・サービスの不具合に関する記述は引用元の投稿時点の状況を紹介したものであり、現在の仕様や品質を評価するものではありません。本記事の情報に基づく判断・行動によって生じた損害について、当サイトは責任を負いかねます。

商標・著作権注記: Claude、Anthropicは Anthropic PBC の商標です。その他記載の製品名・サービス名は各社の商標または登録商標です。引用した記事・投稿の著作権は各著者および運営者に帰属します。当サイトは Anthropic PBC および本記事で言及した各社と提携関係にはなく、いずれの企業からも対価・便益の提供を受けていません。

Share