url_not_in_prior_contextエラーの原因 — Web Fetchが動的URLを拒む理由
Web Fetchツールのurl_not_in_prior_contextエラーは、Claudeが自分でURLを組み立てて取得しようとすると発生します。データ持ち出し対策という設計意図と、正しい回避パターンを解説します。
url_not_in_prior_contextが返る原因は1つに絞れる
url_not_in_prior_contextは、Web Fetchツールがフェッチ先のURLを拒否したときに返るエラーコードです。原因はほぼ1つに絞られます。Claudeが自分でURLを生成・組み立てて渡そうとした場合です。このエラーが起きる仕組みと、意図した通りにURLを取得するための3つの正しい経路を示します。
なぜこのエラーが存在するのか
url_not_in_prior_contextとは、Web Fetchツールが対象URLの出どころを検証し、会話コンテキストに事前に存在しないと判定したときに返すエラーコードです。セキュリティ上の理由から、Web Fetchは会話に一度も登場していないURLを取得できません。許可されるURLの出どころは3つだけです。
- ユーザーメッセージ内のURL
- クライアント側のツール結果に含まれるURL
- 直前のweb_searchまたはweb_fetchの結果に含まれるURL
逆に、Claudeが生成したURLや、コード実行(Code Execution)やBashのようなコンテナ型サーバーツールが返したURLは対象外です。公式ドキュメントは、信頼できない入力と機密データを同じ会話で扱う環境でWeb Fetchを有効にすると、データ持ち出し(exfiltration)のリスクがあると明記しています。Claudeが動的にURLを構成できない設計そのものが、このリスクを減らすための主要な防御です。
エラーの実際の形
Web Fetchツールがエラーに遭遇すると、APIはHTTP 200(成功)を返し、エラーの内容はレスポンス本体のweb_fetch_tool_resultブロックに含まれます。Claudeはこのエラー結果を見た上でターンを続ける仕組みです。url_not_accessibleなど他のエラーコードも同じ構造で返るため、error_codeの値だけが変わります。
{
"type": "web_fetch_tool_result",
"tool_use_id": "srvtoolu_a93jad",
"content": {
"type": "web_fetch_tool_result_error",
"error_code": "url_not_in_prior_context"
}
}HTTPステータス自体は200です。error_codeフィールドをアプリケーション側で明示的に見にいかないと、このエラーは静かに見過ごされます。Claude自身はこのエラー結果を受け取った上でターンを続けます。そのためユーザー向けの応答は「そのページは取得できませんでした」のような形で自然に説明されることが多いです。ただし、ログをerror_code単位で集計していないと、url_not_in_prior_contextが頻発していること自体に気づけません。エージェントのふるまいをモニタリングする際は、web_fetch_tool_resultのうちtypeがweb_fetch_tool_result_errorのものをerror_code別に集計しておくと、どの経路の設計が弱いかを後から特定しやすくなります。
Claudeがこのエラーを踏む典型的な場面
- ページネーションの次のページを
?page=2のように類推してURLを組み立てようとしたとき - 「このパターンのURLで他にも記事がありそうなので取得してみます」のように、Claudeが規則性から新しいURLを推測したとき
- 対象URLがBashやCode Executionツールの実行結果としてしか会話に登場していないとき(この経路は明示的に対象外)
いずれも、URL自体をユーザーが渡していない、あるいはweb_search・クライアントツールの結果として渡していないケースです。Claudeは会話の流れから「次はこのURLを見るのが自然だ」と推測できてしまう場面が多く、推測自体は妥当でもURLの出どころという条件を満たさない限り実行には進めません。エージェントを組んでいて「なぜここでURLを取得できないのか」と感じたときは、まずそのURLが会話のどのブロックに文字列として存在するかを確認するのが早道です。
web_searchを組み合わせると自動的に解決する
web_searchとweb_fetchの両方を有効にしている場合、ユーザーが「READMEを読んで」のようにURLを直接示さずに特定のページを指定すると、Claudeはまずweb_searchでそのページを探します。そして見つかった結果のURLを使ってweb_fetchを呼び出します。この流れではURLが検索結果として会話コンテキストに一度登場してから使われるため、url_not_in_prior_contextには引っかかりません。単体のweb_fetchだけを有効にしている構成で、かつユーザーが具体的なURLを示さない使い方をしていると、Claudeが取得先を選べずこのエラーに行き着きやすくなります。web_searchを併用するかどうかは、単なる機能追加ではなく、このエラーの発生頻度を左右する設計判断です。
両方のツールを渡すリクエストは次の形になります。web_searchのmax_usesとweb_fetchのmax_usesは別枠のカウンターなので、検索と取得それぞれの上限を個別に設計できます。
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-4-8",
"max_tokens": 4096,
"messages": [{
"role": "user",
"content": "quantum computingの最近の記事を探して、いちばん関連度の高い1本を詳しく分析して"
}],
"tools": [
{"type": "web_search_20250305", "name": "Web Search", "max_uses": 3},
{"type": "web_fetch_20250910", "name": "Web Fetch", "max_uses": 5}
]
}'web_fetch単体だけを渡し、web_searchを渡し忘れた状態でこのプロンプトを送ると、Claudeは検索するツールを持たないため取得先URLを決められず、url_not_in_prior_contextに行き着きやすい構成になります。両方を渡しておくのが最短の予防策です。
回避パターン — 使える経路と使えない経路
| 経路 | 使えるか | 補足 |
|---|---|---|
| ユーザーメッセージ内のURL | 使えるか○ | 補足そのまま会話に含めれば十分 |
| web_searchの検索結果URL | 使えるか○ | 補足検索結果として返ったURLは自動的に会話コンテキストに含まれる |
| クライアントツールのtool_result内URL | 使えるか○ | 補足自前のツール実行結果としてURLを返せば、次のフェッチで使える |
| Code Execution / Bashが生成したURL | 使えるか× | 補足コンテナ型サーバーツールの結果はWeb Fetchの対象外と明記されている |
| Claudeが独自に推測・組み立てたURL | 使えるか× | 補足このエラーが防いでいる経路そのもの |
対処は単純です。取得したいURLの候補が複数あるなら、まずweb_searchで検索結果としてURLを会話に載せる(公式が「combined search and fetch」と呼ぶ構成)か、クライアントツールの実行結果としてURLを明示的に返します。なおweb_fetchと自作のクライアントツールを同じターンで同時に呼ぶ構成では、web_fetch自体の実行タイミングがずれる別の仕様が関わります。詳細はtool_useとpause_turnの違いにまとめました。
Claude CodeのWebFetchツールとは別物
Claude CodeにもWebFetchという名前のツールがありますが、これは本記事で扱うMessages APIのweb_fetchサーバーツールとは別の実装です。Claude CodeのWebFetchはローカルの権限システム(allow/denyのドメインルール)で制御される別実装です。同じ「Webフェッチ」という名前でも、動いている面(surface)が違えば挙動もエラーの出方も別物として扱う必要があります。Claude Codeの権限ルールの書き方はClaude Code WebFetch権限ルールにまとめています。
クライアントツールの結果からURLを渡すときの注意
クライアントツールのtool_resultにURLを含めれば、そのURLはprior contextに入ります。自前のツール(社内検索API・ドキュメント管理システムのAPIなど)が候補URLを返す実装であれば、それをそのままtool_resultのcontentに含めるだけで、後続のweb_fetch呼び出しはこのエラーを踏みません。web_searchを有効化する権限がない、あるいは社内ネットワーク限定のドキュメントを対象にしたいといった事情でweb_searchを併用できない場合、この経路が実質的な代替手段になります。
url_not_in_prior_context以外のエラーコードとの違い
url_not_in_prior_context以外にも、Web Fetchは複数のエラーコードを持ちます。いずれも同じweb_fetch_tool_result_errorの形式で返り、error_codeフィールドだけが変わります。
| エラーコード | 意味 | リトライで解決するか |
|---|---|---|
url_too_long | 意味URLが250文字を超えている | リトライで解決するかしない(URL自体の見直しが必要) |
url_not_allowed | 意味ドメインフィルタやrobots.txtによるブロック | リトライで解決するかしない(許可設定の見直しが必要) |
invalid_tool_input | 意味不正なURL形式、またはhttp/https以外のスキーム | リトライで解決するかしない(入力の修正が必要) |
unsupported_content_type | 意味テキスト・HTML・PDF以外の形式を取得しようとした | リトライで解決するかしない(対象URLの見直しが必要) |
max_uses_exceeded | 意味フェッチ回数の上限に達した | リトライで解決するかしない(max_usesの見直しが必要) |
too_many_requests | 意味リクエスト頻度が高すぎる | リトライで解決するかする見込みがある |
unavailable | 意味API側の内部エラー | リトライで解決するかする見込みがある |
too_many_requestsとunavailableの2つは、URLの正当性とは無関係に発生します。同じリクエストを間隔を空けて送り直すだけで解決する可能性があります。一方、url_too_longやurl_not_allowedのようにURLそのものや設定に起因するエラーコードは、何度リトライしても同じ結果になります。まず「リトライで直るか」を切り分けてから対処に着手すると、無駄な再試行を避けられます。
この中でurl_not_in_prior_contextだけが「URLの出どころ」という、コンテンツそのものではなく会話構造を見る検証です。他のエラーコードはURLの形式やアクセス結果を見ているのに対し、この1つだけはURLが会話のどのブロックに事前に存在したかを見ています。他のエラーコードとまとめて対処したい場合はClaude APIのエラーハンドリング設計も参照してください。
このエラーだけが無効化できない防御である理由
allowed_domainsやmax_usesは利用者側でオン・オフや値を調整できる防御です(allowed_domains自体の運用上の落とし穴はallowed_domainsをホモグラフ攻撃で回避される仕組みと対策で扱っています)。一方、URLの出どころ検証はツールの設定項目として公開されておらず、無効化するオプションもありません。攻撃面を減らす目的で見ると、Web Fetchが持つ複数の防御のうち、これだけが常時有効な唯一の仕組みと言えそうです。裏を返せば、Claudeにこのエラーを踏ませないようにURLの出どころを整えるのは、開発者側の実装で吸収する以外に選択肢が無い制約ということになります。
まとめ
url_not_in_prior_contextは、Claudeが自分でURLを組み立てて取得しようとしたときに発生する、無効化できないURL出どころ検証です。ユーザーメッセージ・web_searchの検索結果・クライアントツールのtool_result、いずれかの経路でURLを会話に載せてからフェッチを依頼すれば回避できます。往復の実装を自分で書きたくない場合はTool RunnerやAdvanced Tool Useのツール群も検討候補になります。