Claude web_searchのエラーコード一覧と対処法
Claude APIのweb_searchサーバーツールが返す6種類のエラーコードと、200成功扱いで返る特殊な形式、コード別の対処方針をまとめます。
Claude APIのweb_searchツールがエラーを起こしたとき、レスポンス自体は200で返ってきます。is_errorフラグを見るクライアントツールの実装をそのまま流用すると、エラーを検知できずに素通りさせてしまいます。この記事ではweb_searchが返す6種類のエラーコードの意味と、コードごとの対処方針をまとめます。
web_searchのエラーはis_errorを使わない
クライアントツールのエラーはtool_resultブロックに"is_error": trueを立てて表現します。ところがweb_searchのようなサーバーツール(Claudeの実行環境内でAnthropicが直接動かすツール)は違う形式を使います。公式ドキュメントは次のJSON構造を示しています。
{
"type": "web_search_tool_result",
"tool_use_id": "srvtoolu_a93jad",
"content": {
"type": "web_search_tool_result_error",
"error_code": "max_uses_exceeded"
}
}APIレスポンスのステータスコードはエラー時も200のままです。エラーかどうかはcontentのtypeがweb_search_tool_result_errorになっているかで判定します。正常時のcontentは検索結果のリストですが、エラー時は単一のエラーオブジェクトに置き換わります。検索が成功して0件だった場合はエラーではなく空のリストが返るので、「contentが空かどうか」だけでエラー判定をすると、0件ヒットを誤ってエラー扱いしてしまいます。判定に使うべきはcontent.typeの値です。
この設計は他のサーバーツールにも共通する考え方です。クライアントツールはアプリ側が実装を持つため、失敗の伝え方をアプリ側で統一できます。一方サーバーツールはAnthropicの実行環境内で動くため、失敗の形式そのものがツールごとの仕様として公式ドキュメントに定義されています。web_searchを使うアプリを書くなら、まずこの前提の違いを押さえておくと、あとから来る個々のエラーコードの意味も理解しやすくなります。
6つのエラーコードの意味
error_codeが取りうる値は次の6種類です。
| error_code | 意味 |
|---|---|
too_many_requests | 意味レート制限を超過した |
invalid_tool_input | 意味検索クエリのパラメータが不正 |
max_uses_exceeded | 意味max_usesで設定した検索回数の上限に達した |
query_too_long | 意味クエリが最大長を超えている |
request_too_large | 意味検索リクエスト自体が大きすぎる(典型的にはドメインフィルタが長すぎる場合) |
unavailable | 意味Anthropic側の内部エラー |
too_many_requestsとunavailableは一時的な障害なので再試行が有効です。invalid_tool_inputとquery_too_longはClaudeが生成したクエリ自体に問題があるケースです。max_uses_exceededは、アプリ側で設定した上限にツール利用側が到達した状態を指します。request_too_largeだけは検索クエリではなく、allowed_domainsやblocked_domainsで渡したドメインフィルタの一覧が肥大化しているときに出ます。
リクエスト全体が400で落ちるケースと区別する
error_codeが入るのは、リクエスト自体は受理されて検索の実行段階で失敗したときだけです。それより手前でリクエストの形式そのものが不正な場合は、通常の400 invalid_request_errorとしてリクエスト全体が拒否されます。この2つを混同すると、error_codeだけを見るエラーハンドラでは400エラーを取りこぼします。
400で落ちる代表的な原因は次のとおりです。
- 組織の管理者がClaude Consoleで
web_searchを無効化している(この場合はリクエストそのものがweb search is not enabledという400で拒否される) allowed_domainsとblocked_domainsを同時に指定した(どちらか一方のみ許可)user_locationのcountryにサポート外の国コードを渡した- プログラム的ツール呼び出しをサポートしないモデルで、
allowed_callers: ["direct"]を明示せずにweb_searchを直接呼んだ - 複数ターンの会話で、前のターンの検索結果に含まれる
encrypted_contentが欠落または改変されている
これらはアプリ側の設定ミスや実装漏れが原因になりやすく、error_codeのハンドリングを直しても解消しません。まず400かどうかで大枠を切り分け、200で返ってきたときだけerror_codeの値で処理を分岐する、という2段階の判定にするのが実装として素直です。
allowed_domainsとblocked_domainsは、どちらもスキームを含まないベアドメインか、そこにパスを続けた形(example.comやexample.com/blog)で渡します。この形式から外れた値を渡すと、request_too_largeではなく手前の400で弾かれることもあります。まずはドメイン一覧の書式そのものを疑う価値があります。
ドキュメントによってコード名の一覧が食い違う
web_searchのエラーコードは、実は公式ドキュメント内で2箇所に書かれていて、内容が完全には一致しません。ツール共通の一般的なエラー処理ページ(Handle tool calls)は次の5種類を挙げています。
too_many_requestsinvalid_inputmax_uses_exceededquery_too_longunavailable
一方、web_searchツール専用ページの「Errors」節は、先ほどの表で示した6種類を挙げています。名称もinvalid_inputではなくinvalid_tool_inputになっています。つまり一般ページには載っていないrequest_too_largeが専用ページには存在し、無効な入力を示すコードの名前自体も違うことになります。
どちらが最新の実装を反映しているかを確定させる材料は、公式ページ自体には書かれていません。ただしweb_search固有の詳細な仕様(JSON構造の例、ストリーミング時の挙動、課金ルール)を持つのは専用ページのほうです。実装をこれから書くなら、専用ページの6種類・invalid_tool_inputという名前を正として実装しておくのが堅実です。想定していないコード文字列が来た場合に備え、ログを残して安全側に倒すデフォルトの分岐も用意しておきます。一般ページの5種類だけを前提にしたコードを書くと、request_too_largeが来たときにどの分岐にも当てはまらず、意図しない挙動になりかねません。
コードでの実装例
Pythonでレスポンスのcontentブロックを走査し、web_search_tool_resultの中身がエラーかどうかで分岐する例です。
for block in response.content:
if block.type == "web_search_tool_result":
result = block.content
if isinstance(result, dict) and result.get("type") == "web_search_tool_result_error":
code = result["error_code"]
if code in ("too_many_requests", "unavailable"):
# 一時的な障害。バックオフして再試行
retry_with_backoff()
elif code == "max_uses_exceeded":
# このターンの検索予算を使い切った
notify_budget_exhausted()
elif code in ("invalid_tool_input", "query_too_long"):
# クエリ自体の問題。Claudeに作り直させる
log_bad_query(result)
elif code == "request_too_large":
# ドメインフィルタが大きすぎる
shrink_domain_filters()
else:
# 正常な検索結果(0件ヒットならこちらも空リストで届く)
handle_results(result)error_codeは文字列の生値で届くので、if文で直接比較する分には問題ありません。ただし複数のフィールドをまとめて比較・キャッシュ・ログ差分に使う実装では話が別です。JSON文字列同士をそのまま比較するのは避け、フィールド単位で比較してください。理由はJSON文字列比較で起きるエスケープ差分の罠にまとめています。
使い分け早見表 — コード別の推奨対応
| error_code | 推奨対応 |
|---|---|
too_many_requests | 推奨対応指数バックオフで再試行 |
invalid_tool_input | 推奨対応クエリを検証してから再送、またはClaudeに再入力を促す |
max_uses_exceeded | 推奨対応max_usesの設定値を見直すか、ユーザーに追加検索が必要と伝える |
query_too_long | 推奨対応クエリを短縮して再送 |
request_too_large | 推奨対応allowed_domains / blocked_domainsの件数を削減 |
unavailable | 推奨対応再試行。頻発する場合はサポートに連絡 |
検索が長引くとpause_turnで一時停止することもある
エラーとは別に、検索の実行に時間がかかる場合、APIはstop_reason: "pause_turn"を返してターンを一時停止することがあります。これはエラーではなく、続きを送るとそのまま検索が再開する正常な中断状態です。対応は単純で、一時停止されたアシスタントメッセージをそのまま次のリクエストに含めて送り直すだけです。
もう一つ注意したいのが、同じターンでweb_searchとクライアントツールを両方呼び出した場合の挙動です。この組み合わせではstop_reasonがpause_turnではなくtool_useになり、検索はまだ実行されません。まずクライアントツールの結果を返すと、次のリクエストで検索が実行されます。このtool_useはweb_searchのエラーとは無関係な正常フローです。error_codeの有無で判定を分けていれば、エラーハンドリングの実装時に誤ってエラー扱いすることはありません。
Batches APIやストリーミングでも同じ形式
Messages Batches APIからweb_searchを呼ぶ場合も、料金体系やerror_codeの形式は通常のMessages APIと同じです。ただし共有キャパシティを保護するため、組織単位でWeb検索のリクエストがスロットリングされる場合があり、検索を多く含む大きなバッチは完了までに時間がかかることがあります。頻繁にスロットリングの影響を受ける場合は、Claude Consoleのレート制限ページで組織の上限を確認し、上限引き上げをサポートに相談する選択肢もあります。
ストリーミングを使う場合、検索結果はweb_search_tool_resultというcontent blockとしてcontent_block_startイベントに含まれて届きます。エラー時のJSON構造自体は非ストリーミングと同じなので、ストリームの該当イベントを受け取った時点で同じ判定ロジックをそのまま適用できます。
課金はエラー発生時にどうなるか
Web検索は1,000検索あたり10ドルの従量課金で、検索1回につき結果件数に関わらず1回分としてカウントされます。検索中にエラーが発生した場合、その検索は課金対象になりません。再試行を実装する際、失敗した検索分の課金を心配してリトライ回数を絞る必要はないという意味では、実装をシンプルに保てます。
Claude Codeやclaude.aiのWeb検索とは別物
この記事で扱っているのは、Messages APIからweb_searchツールを直接呼び出したときのエラー形式です。Claude Codeやclaude.aiのWeb検索は面ごとに実装も挙動も異なり、生のerror_codeをそのまま見せるとは限りません。エンドユーザー向けの挙動の違いはClaude Web検索の使い方にまとめています。
ツール呼び出し全般の設計はAnthropic Advanced Tool Useを、会話履歴の不整合など別系統のtool_use関連エラーはthinking block mismatchエラーの原因とrewindでの直し方も参考にしてください。
よくある質問
エラーコードのハンドリングをテストするにはどうすればよいか
too_many_requestsのようなレート制限系のコードは、通常の利用では意図的に再現しにくいエラーです。max_usesを極端に小さい値(たとえば1)に設定してから複数回検索が必要なプロンプトを送れば、max_uses_exceededは狙って再現できます。それ以外のコードについては、実装側でエラー分岐のユニットテストをerror_codeの文字列を直接渡すモックレスポンスとして書くほうが現実的です。
is_errorをまったく見なくてよいか
web_searchのようなサーバーツールに関しては見る必要がありません。公式ドキュメントも「サーバーツールについてはis_errorの結果をハンドリングする必要がない」と明記しています。ただし同じアプリの中でクライアントツール(自前で実装した関数呼び出し)も併用している場合は話が別です。そちらのエラーは引き続きis_error: trueで表現されるので、ツールの種類ごとに判定方法が違う点を実装時に混同しないよう注意してください。
まとめ
web_searchのエラーはis_errorフラグではなく、content.typeがweb_search_tool_result_errorかどうかで判定します。エラーコードはtoo_many_requests / invalid_tool_input / max_uses_exceeded / query_too_long / request_too_large / unavailableの6種類で、一時的な障害(too_many_requests unavailable)、クエリ自体の問題(invalid_tool_input query_too_long)、設定起因(max_uses_exceeded request_too_large)におおまかに分類できます。加えて、リクエストの形式そのものが不正なときはerror_codeではなく通常の400エラーとしてリクエスト全体が拒否される点も忘れずに切り分けてください。