Claudeの400エラー:tool_useに対応するtool_resultがない場合の直し方

ClaudeやOpenCodeでtool_resultエラーが出る場合に、呼び出しID・メッセージ順序・並列ツールの結果・中断した会話を確認する手順を解説します。

暖かいベージュの背景に明るい紙を配置し、鍵とひもの線画、幾何学模様、英語タイトル「Claude Tool Results」を添えた表紙。

Claudeがtool_useに対応するtool_resultがないと返す場合、通常はプロンプトの言い換えではなく、ツール呼び出しを含む会話の構造を調べます。ネイティブMessages APIでは、assistantがクライアントツールを呼び出し、その次のuserメッセージで同じIDの結果を返します。同じリクエストを再試行する前に、この対応関係を確認してください。

本記事は、独自実装やOpenCodeなどのクライアントで起きる、この種類のエラーを扱います。OpenCodeのHTTP 400がすべて同じ原因という意味ではありません。以下のルールは2026年9月14日に確認したClaudeのツール呼び出し処理の公式文書に基づきます。例は説明用に作成したメッセージ断片であり、実際のAPIテストのログではありません。

最初に対応していないIDを探す

エラー全文を読み、指摘されたtool-use IDを直前のassistantメッセージ内で探します。続いて次のuserメッセージを確認します。tool_result.tool_use_idは、そのIDと完全に一致する必要があります。ツール名ではIDの代わりになりません。

ネイティブClaudeプロトコルでは、ツール結果はuserメッセージ内のcontentブロックです。この形式にネイティブのrole: "tool"はありません。別プロバイダーの形式も扱うアダプターでは、roleとフィールドをそのまま転送せず、必要な変換が行われているか確認します。

確認項目正しい対応よくある問題
IDtool_use.idtool_result.tool_use_idが一致別のIDを生成した、IDが途中で切れた
メッセージ順assistantの呼び出しの直後にuserの結果間に別のメッセージを挿入した
複数の呼び出しすべてのクライアントツール呼び出しに結果がある最初の結果しか保存していない
userのcontent内の順序通常のテキストより先にツール結果結果の前にテキストブロックがある

正しい最小メッセージ断片

このJSONは関係するメッセージだけを示しています。完全なリクエストには、使用するモデル、ツール定義、トークン上限、その他の会話履歴も必要です。結果の値は説明用の架空データであり、実際のツール実行の代わりに使ってはいけません。

[
  {
    "role": "assistant",
    "content": [
      {"type": "tool_use", "id": "toolu_demo", "name": "lookup", "input": {"key": "demo"}}
    ]
  },
  {
    "role": "user",
    "content": [
      {"type": "tool_result", "tool_use_id": "toolu_demo", "content": "demo result"}
    ]
  }
]

チャット画面に表示された文字列からassistantメッセージを作り直さず、APIが返した構造化content全体を保存します。モデルと処理手順によってはthinkingデータなど、他のブロックも会話内に保持する必要があります。署名検証は別の問題です。Claudeのthinking署名ガイドで扱っています。

並列呼び出しでは、結果をそろえて返す

一つのassistantメッセージが二つのクライアントツールを要求したら、両方の結果を集め、その直後のuserメッセージにまとめます。一つ目の結果を送って別のassistantターンを挟み、その後に元の呼び出しの二つ目の結果を返す形にはしません。説明用のuserテキストが許可される場合も、結果ブロックの後に置きます。

公式のツール利用トラブルシューティングには、サーバーツールを混在させる場合の説明もあります。同じラウンドで未完了のサーバーツールがある場合、userメッセージにはクライアントツールの結果だけを入れ、リクエストのtools配列を維持します。クライアントツールだけの最小例を、あらゆるサーバーツールの処理に当てはめないでください。

ツールの失敗を、成功したように見せない

検索やコマンドが失敗しても、ツール結果の対応関係は正しく表現できます。文書で定められたクライアントツールの形式に従い、同じIDにis_error: trueと正確なエラー説明を付けて返します。プロトコル上の対応関係と、処理そのものが成功したかどうかは別の確認事項です。

クライアントが中断した場合は、ツールが実際に動いたかを先に調べます。画面上のタイムアウトは、ファイル書き込み、デプロイ、外部リクエストが実行されなかった証拠にはなりません。副作用のある操作を繰り返す前に、対象の状態を確認してください。検証を通すために成功結果を捏造したり、重要な操作を自動的に二度実行したりしてはいけません。

開発中の再現には、破棄できる会話で無害な検索を使います。読み取り専用の例なら、書き込みや取引を再実行せずに対応関係の不具合を調べられます。クライアントのバージョンと、中断の直前・直後のメッセージを記録します。

壊れた会話履歴を慎重に復旧する

修復を試す前に、該当する履歴のローカルコピーを保存します。元の結果が残っていれば、クライアントが対応する復旧方法で、IDが正しく対応したメッセージを戻します。安全に直せない場合は、確認済みの作業と未処理の操作を短くまとめて新しい会話を作り、元の会話も参照用に残します。

ツールブロックを無作為に削除すると、モデルが把握する実行状態が変わることがあります。そのため、会話ファイルをすべて削除する方法を標準の対処にはしません。issueを提出するなら、role、contentの種類、対応するIDが分かる機密情報を除いた最小限のメッセージ列を添えます。APIキー、非公開のツール引数、機密性のある結果は除いてください。

クライアント更新のリリースノートを確認する価値はありますが、本記事はすべての事例を直す特定バージョンを示すものではありません。過去のissueが示すのは、ある構成で問題が発生したという事実です。最新リリースにも同じバグが残っている証拠にはなりません。

再試行だけでは直らない理由

APIはモデルのターンを続ける前に会話構造を検証します。対応の取れていない同じメッセージ列を送り直しても、その構造は変わりません。これはプロトコルのルールから導く説明であり、すべてのクライアントの再試行実装を計測した結果ではありません。

HTTP 429やサービスの過負荷では、別の調査が必要です。この手順を適用する前に、実際のステータスとエラー本文を確認します。別のアクセスエラーについてはmodel-not-foundの診断(英語)を参照できますが、対象プロトコルが異なるため、Claudeのツールメッセージ対応と混同しないでください。

よくある質問

ツールのエラー結果でも対応関係の要件を満たせますか?

はい。実際の失敗を表す結果を、元のtool-use IDに対応させられます。次のメッセージで失敗を正しく記録するために、処理が成功している必要はありません。

ネイティブClaude APIでrole toolを使いますか?

いいえ。ネイティブのクライアントツール結果はuserメッセージのcontentブロックです。OpenAI互換アダプターが別の形式を公開する場合もあるため、実際にリクエストを受け取るエンドポイントのプロトコルに従ってください。

新しい会話を作れば完全に直りますか?

壊れた履歴の影響は切り分けられますが、結果を落とし続けるアダプターは直りません。新しい会話に頼る前に、不正なメッセージ列を作ったシリアライザーやクライアントの処理を確認してください。

よくある質問

同じtool_resultエラーを再試行しても直らないのはなぜですか?
対応関係が崩れたメッセージ列を再送しても無効なままだからです。先にIDの対応と順序を修正します。
ネイティブClaude APIではツール結果をどこに入れますか?
userメッセージのcontentブロックに入れ、直前のassistantのtool_use IDとtool_use_idを一致させます。
ツールの実行エラーも返せますか?
はい。成功した結果を作り上げず、元のIDに対して実際の失敗を表す結果を返します。