Claude Code WebFetchのキャッシュとタイムアウト — 15分の既定TTLと専用設定が無い理由
WebFetchが古い情報を返す・失敗する原因をキャッシュTTL・変換の仕組み・リダイレクト処理・リトライ動作から切り分けます。
WebFetchが数分前に更新したはずのページを古いまま返す、あるいは特定のURLだけ失敗する。原因を探ろうとして「タイムアウト値を伸ばせばいいのでは」と考えがちですが、WebFetch専用のタイムアウト設定というものは存在しません。挙動を決めているのはキャッシュの有効期限、HTMLをMarkdownへ変換してから要約する処理、そしてリダイレクトやAPI過負荷時のリトライです。この4つを切り分ければ、多くの「古い」「失敗する」は原因が特定できます。
WebFetchはURLを取得してから3段階で処理する
WebFetchは取得・Markdown変換・抽出の3段階でページを処理します。URLと「何を抽出したいか」を書いたプロンプトを受け取ってページを取得し、サーバーがHTMLを返した場合はMarkdownへ変換し、その内容に対してプロンプトを小型で高速なモデルに実行させて結果を返します。Claudeが受け取るのは多くの場合、元のページそのものではなくこのモデルの回答です。
この変換ステップは設定で変えられません。つまりWebFetchは設計上情報が欠落します。「このページには◯◯についての記載がない」という結果が返ってきても、実際にはページに書かれているのに抽出プロンプトがそれを尋ねていなかっただけ、というケースがあります。より具体的なプロンプトを添えて再度WebFetchを呼ぶか、Bash経由のcurlで生のページを取得するのが対処法です。
HTTPで指定したURLは自動的にHTTPSへ引き上げられます。これはリダイレクト処理とは別の仕組みで、URLのスキームだけを見て起きます。
取得リクエストにはClaude-Userで始まるUser-Agentヘッダーと、HTMLよりMarkdownを優先するAcceptヘッダーが付きます。コンテンツネゴシエーションに対応しているサーバー(公式ドキュメントサイトやGitHubの一部エンドポイントなど)は、このヘッダーを見てMarkdownを直接返します。この場合、Claude Code側でのHTML変換ステップを経ずに済みます。サイトによって、最初からMarkdownが返るものと、HTMLを受け取ってClaude Code側で変換するものに分かれます。変換を通ったページのほうが、表や入れ子リストの崩れが目立ちます。逆にUser-Agentでボットを弾くサイトでは、WebFetchの取得自体がその時点で失敗します。
キャッシュは既定15分 — 古い情報が返る一番の原因
WebFetchは同じURLへの応答を既定で15分間キャッシュします。取得し直したいのに数分前と同じ内容が返ってくるときは、まずこのキャッシュを疑います。ページ側を更新した直後にWebFetchで確認しても、キャッシュの有効期限内なら更新前の内容が返り続けます。
Claude Code v2.1.233以降では、環境変数CLAUDE_CODE_WEBFETCH_CACHE_TTL_MSでこの保持時間をミリ秒単位で変更できます。既定値は900000(15分)です。指定できるのは素の数字だけで、0や小数、その他の書き方を渡した場合は既定値のまま動きます。つまりキャッシュを無効化する専用の値は無く、短くする方向でしか回避できません。
この環境変数はClaude Codeの起動時に一度だけ読み込まれます。settings.jsonのenvブロックで値を変えても、次にclaudeを起動するまでは反映されません。実行中のセッションで値を変えても効果が無いのはこのためです。
WebFetchに専用のタイムアウト設定は無い
「WebFetchが遅いページで固まる」ときにタイムアウト値を探しても、公式ドキュメントにWebFetch専用のタイムアウト変数は挙げられていません。Claude Codeが持つタイムアウト系の環境変数は、性質が異なる別のものです。
| 変数 | 対象 | WebFetchへの関係 |
|---|---|---|
BASH_DEFAULT_TIMEOUT_MS / BASH_MAX_TIMEOUT_MS | 対象Bashツールが実行するシェルコマンド | WebFetchへの関係無関係。curlをBashで直接呼ぶ場合のみ影響する |
API_TIMEOUT_MS | 対象Anthropic APIへのリクエスト全般(既定10分) | WebFetchへの関係WebFetch内部の抽出処理もAPIリクエストの一種だが、WebFetch固有の挙動としては文書化されていない |
CLAUDE_CODE_WEBFETCH_CACHE_TTL_MS | 対象WebFetchの応答キャッシュの保持時間 | WebFetchへの関係キャッシュの寿命であり、取得や抽出そのものの待ち時間ではない |
固まって見える場合の多くは、後述するAPI過負荷時のリトライが背後で動いているケースです。バックオフを挟みながら再試行しているあいだ、体感としては「タイムアウトしていない」まま待たされます。
リダイレクトと大きなページの扱い
取得先のURLが別ホストへリダイレクトする場合、WebFetchはそのリダイレクトを自動ではたどりません。元のURLとリダイレクト先を示すテキストを結果として返すだけです。リダイレクト先の内容も見たい場合、Claudeはそのリダイレクト先URLに対して2回目のWebFetch呼び出しを自分で発行します。ホストをまたぐリダイレクトは、1回のWebFetch呼び出しでは完結しません。
ページが大きい場合は、処理に入る前に一定の文字数で切り詰められます。長大なドキュメントやCHANGELOGを丸ごと読ませたいのに一部しか反映されないときは、この切り詰めが原因になっている可能性があります。ページを分割して複数回WebFetchするか、該当箇所のURLアンカーを直接指定するほうが確実です。
抽出処理が失敗したときの挙動
WebFetchが内部で実行する抽出リクエストがAPIの過負荷(overloaded)に当たった場合、Claude Codeはバックオフを挟みながら自動でリトライします。それでも失敗が続いた場合はエラー結果として返り、Claudeにはページの内容ではなくエラーであることが伝わります。
Claude Code v2.1.212より前のバージョンには、このエラー時にAPIのエラーテキストがあたかも抽出されたページの内容であるかのようにClaudeへ渡ってしまう不具合がありました。古いバージョンを使っている場合、WebFetchの結果が明らかに文脈と噛み合わないテキストを返してきたら、実際にはエラーが起きているのにページの内容として扱われている可能性があります。v2.1.212以降ではこの問題は解消され、失敗は失敗として区別されます。
権限プロンプトとドメイン許可の基礎
Manual・acceptEditsの権限モードでは、WebFetchは取得前に確認を求めます。ただしすでに許可・拒否ルールがあるドメインや、組み込みで事前承認されている一部の公式ドキュメントドメインは確認なしで取得されます。ドメイン単位の許可・拒否ルールの書き方、裸のWebFetchルールとWebFetch(domain:*)の違い、サンドボックスのネットワーク許可リストとの連動は、Claude Code WebFetch権限ルールで扱っています。本稿のキャッシュ・変換・リトライの挙動とは独立した設定なので、あわせて確認すると「取得できない」原因の切り分けが早くなります。
許可・拒否ルールとは別に、WebFetchは取得の前に必ずドメイン安全性チェックを通ります。このチェックはホスト名だけをapi.anthropic.comへ送り、Anthropicが管理するブロックリストと照合します。通過したホスト名は5分間キャッシュされます。モデルプロバイダーを問わず必ず実行されるため、社内ネットワークがapi.anthropic.comをブロックしている環境では、許可ルールの設定に関わらず取得前の時点でWebFetchが失敗します。この場合はapi.anthropic.comを許可するか、settings.jsonでskipWebFetchPreflightをtrueにします。ただし無効化するとブロックリストを参照せずに取得するため、ドメイン単位の許可ルールと併用します。
なお、Claude Desktop上のCoworkセッションでは、組み込みのWebFetchツールではなくmcp__workspace__web_fetchという別のツールが使われます。WebFetch宛てのdenyルールはこちらにも適用されますが、キャッシュTTLや抽出処理の細部は同じ実装とは限りません。ここまでの挙動はClaude CodeのWebFetchツールについてのものだと理解しておきます。
症状から原因を切り分ける
WebFetchの不調は症状ごとに原因が絞り込めます。
| 症状 | 疑う原因 | 対処 |
|---|---|---|
| 数分前に更新したはずのページが古いまま返る | 疑う原因キャッシュ(既定15分) | 対処少し待つかCLAUDE_CODE_WEBFETCH_CACHE_TTL_MSを短く設定し再起動する |
| 「そのページには書かれていない」と言われるが実際は書いてある | 疑う原因抽出プロンプトが尋ねていない、または本文が切り詰められている | 対処より具体的なプロンプトで再取得するか、Bashのcurlで生ページを見る |
| 長いドキュメントの一部しか反映されない | 疑う原因大きなページの切り詰め | 対処ページを分割して複数回取得するか、該当セクションのURLを直接指定する |
| 別ドメインのURLなのに1回で内容が返らない | 疑う原因クロスホストのリダイレクト | 対処2回目のWebFetch呼び出しが自動で発行されるのを待つ |
| 結果が文脈とまったく噛み合わない | 疑う原因v2.1.212より前のエラーリーク不具合 | 対処Claude Codeを最新版へ更新する |
| 特定ドメインだけ毎回確認を求められる、または拒否される | 疑う原因権限ルールまたはサンドボックスのドメイン許可設定 | 対処前節のドメイン単位の許可設計を見直す |
| 社内ネットワークでどのドメインも取得できない | 疑う原因取得前のドメイン安全性チェックがapi.anthropic.comへ到達できない | 対処api.anthropic.comを許可するか、settings.jsonのskipWebFetchPreflightをtrueにする |
よくある質問
WebFetchの代わりにBashでcurlを使うとキャッシュや切り詰めは回避できますか
回避できます。WebFetchのキャッシュ・変換・切り詰めはツール固有の仕組みなので、Bash経由のcurlはこれらの影響を受けません。ただし取得したHTMLを自分で読める形に整形する手間が増え、Bashの実行自体は別の権限ルール(Bash)が対象になります。
ドメイン安全性チェックで通過したホスト名のキャッシュと、応答本体のキャッシュは同じものですか
別のキャッシュです。ドメイン安全性チェックが「このホストへ送っていいか」を判定した結果は5分間だけ保持されます。一方、CLAUDE_CODE_WEBFETCH_CACHE_TTL_MSが対象にしているのは取得したページの応答内容そのもので、既定15分保持されます。前者は許可判定のキャッシュ、後者は取得結果のキャッシュで、TTLも役割も別レイヤーです。
skipWebFetchPreflightをtrueにすると何を失いますか
ドメイン安全性チェック自体を丸ごと飛ばすため、Anthropicが管理するブロックリストとの照合が行われなくなります。社内ネットワークがapi.anthropic.comへの到達をブロックしていて許可判定そのものができない場合の回避策であり、常時有効にする設定ではありません。許可・拒否ルール(WebFetch(domain:*)等)は別レイヤーなので、これと併用して取得先を絞り込むほうが安全です。
Coworkのweb_fetchでも同じTTLが効きますか
Claude Desktop上のCoworkセッションでは、組み込みのWebFetchツールではなくmcp__workspace__web_fetchという別のツールが使われます。WebFetch宛てのdenyルールはこちらにも適用されますが、キャッシュTTLや抽出処理の細部が同じ実装かどうかは公式ドキュメントに明記されていません。
サブエージェントが呼んだWebFetchもキャッシュを共有しますか
公式ドキュメントにキャッシュの共有範囲についての記載はありません。サブエージェントのプロンプトキャッシュは別扱い(separate cache)と明記されているため、同じ類推がWebFetchの応答キャッシュにもそのまま当てはまるとは限りません。
まとめ
WebFetchの不調は「遅い・古い・失敗する」のどれに当てはまるかを最初に切り分けると、キャッシュのTTL・変換処理での情報欠落・リダイレクトの2段構え・API過負荷時のリトライ・取得前のドメイン安全性チェックのどこが原因かが絞り込めます。環境変数全体の見取り図はClaude Code環境変数リファレンス、Web検索側の挙動はClaude Web検索の使い方、ネットワークアクセス全体の設計はClaude Codeのサンドボックス設計にまとめています。