CLAUDE LABEN
2.1.268 — Claude Code の最新版が出ました。目玉は新機能ではなく、互換エンドポイントを使う人を2.1.265 からずっと止めていた不具合の修正ですBASE_URL — ANTHROPIC_BASE_URL を立てた第三者の互換エンドポイントが、全ターン HTTP 400 になっていました。設定を疑う前に版を上げてくださいWEBFETCH — 応答を閉じないサーバーで WebFetch が永久に待つ問題に、300秒の期限が付きました。CLAUDE_CODE_WEBFETCH_DEADLINE_MS で変えられますSECRET — MCP 設定の ${VAR} から解決した秘密情報が /mcp や claude mcp list に表示されていました。画面を共有する方はご確認くださいCPU — アイドル状態の長いセッションが CPU コアを張り付かせるビジーループも直っています。ファンが回り続ける心当たりがある方へRESUME — --continue と --resume が SessionStart フックを待たずに会話を表示するようになりました。起動まわりの体感が変わります2.1.268 — Claude Code の最新版が出ました。目玉は新機能ではなく、互換エンドポイントを使う人を2.1.265 からずっと止めていた不具合の修正ですBASE_URL — ANTHROPIC_BASE_URL を立てた第三者の互換エンドポイントが、全ターン HTTP 400 になっていました。設定を疑う前に版を上げてくださいWEBFETCH — 応答を閉じないサーバーで WebFetch が永久に待つ問題に、300秒の期限が付きました。CLAUDE_CODE_WEBFETCH_DEADLINE_MS で変えられますSECRET — MCP 設定の ${VAR} から解決した秘密情報が /mcp や claude mcp list に表示されていました。画面を共有する方はご確認くださいCPU — アイドル状態の長いセッションが CPU コアを張り付かせるビジーループも直っています。ファンが回り続ける心当たりがある方へRESUME — --continue と --resume が SessionStart フックを待たずに会話を表示するようになりました。起動まわりの体感が変わります
記事一覧/Claude Code
Claude Code/2026-09-12中級

巡回タスクが朝まで返らなかった原因は、WebFetch の待ち時間に上限がなかったことでした

Claude Code v2.1.268 で WebFetch に 300 秒の期限が付きました。応答を閉じないサーバーに当たると無人実行がどこで止まるのか、CLAUDE_CODE_WEBFETCH_DEADLINE_MS の 0 がなぜ「待たない」ではないのかを、手元で再現できる形で整理します。

Claude Code254WebFetch2環境変数6無人実行6タイムアウト3

ある朝、いつもの時刻にログを開きましたら、前の晩の一行目だけが残っておりました。個人開発のアプリで使っている依存ライブラリのリリースノートと、ストアの規約ページを夜のあいだに巡回させている小さなタスクです。

プロセスは生きておりました。CPU も食っておりません。エラーも出ておりません。ただ、返ってこないのです。

原因は、巡回先のうち一つが応答を開いたまま閉じないサーバーだったことでした。そして当時の Claude Code は、そういう相手をいつまでも待つようにできておりました。

返ってこないときに、まずどこを見るか

止まったタスクを前にすると、プロンプトや権限設定を疑いたくなります。私も最初はそちらから手を付けました。結果は芳しくありませんでした。プロンプトを削っても、権限を広げても、翌朝の状態は同じだったのです。

いま思えば、返ってこないという症状をエラーの一種として数えていたことが、遠回りの始まりだったのかもしれません。順番が違っておりました。返ってこない不具合では、書いた内容より先に「誰が待っているか」を特定します。 待っているのが自分の書き方なのか、道具なのか、相手のサーバーなのかで、直す場所がまるで変わります。

見る順番はこうしております。

  1. ログの最終行。どのツール呼び出しの直後で止まっているか
  2. プロセスの状態。落ちているのか、生きたまま待っているのか
  3. その行に出ている URL を、手元の curl で同じように叩き直すこと

3 番目で答えが出ることが多いです。ブラウザで開けるページでも、curl で叩くと終わらないことがあります。

# --max-time を付けずに叩くと、こちらも同じように返ってきません
curl -sS -o /dev/null -w 'http=%{http_code} total=%{time_total}s\n' \
  --max-time 20 "https://example.com/release-notes"
echo "exit=$?"

--max-time に当たると curl は終了コード 28 を返します。ここで 28 が出るなら、詰まっているのは自分の書き方ではありません。

応答を閉じないサーバーを、手元で作ってみます

相手のサーバーを再現できると、対策の効きを確かめられます。依存を足さずに、これだけで用が足ります。

// slow-server.mjs — ヘッダと途中までの本文を返し、以後は閉じないサーバー
import { createServer } from "node:http";
 
createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
  res.write("<html><body><p>preparing the report…</p>");
  // 本文を書き切らず、res.end() も呼ばないまま放置します
}).listen(8080, () => {
  console.log("listening on http://127.0.0.1:8080");
});

node slow-server.mjs で起動して、先ほどの curlhttp://127.0.0.1:8080 へ向けると、20 秒きっかりで 28 が返ります。同じ URL を Claude Code の WebFetch に渡すと、v2.1.268 より前では待ち続けます。

これが、夜のあいだに一度しか起きない類の詰まり方でした。日中に手で回しているときは、返ってこないと気づいた時点で自分が止めます。無人で走らせていると、止める人がいないのです。

0 は「待たない」ではなく「期限を外す」です

v2.1.268(9 月 10 日)で、この待ち方に区切りが入りました。公式のチェンジログには、応答を閉じ切らないサーバーで WebFetch が無期限に待つ問題を修正し、取得は 300 秒で失敗するようになったこと、そして CLAUDE_CODE_WEBFETCH_DEADLINE_MS で期限を上書きできることが書かれております。

ここで私は一度つまずきました。0 を「待たずに即座に打ち切る」の意味だと読んで、巡回タスクの環境変数に置いてしまったのです。翌朝の状態は、修正前と同じでした。0 は期限を無効にする指定でした。

設定値WebFetch の待ち方向く場面
未設定300 秒(既定)で失敗します手元で対話しながら使うとき
6000060 秒で失敗します取得先が多い巡回。早めに諦めさせたいとき
0期限が外れ、閉じない応答を待ち続けます旧来の挙動へ戻したいときのみ

巡回タスクでは、既定の 300 秒でも長すぎることがあります。取得先が 12 件あって、そのうち 3 件が閉じないサーバーだった場合、それだけで 15 分が待ち時間に消えるからです。私は 60 秒に寄せております。

{
  "env": {
    "CLAUDE_CODE_WEBFETCH_DEADLINE_MS": "60000"
  }
}

設定ファイルに置くほどでもないときは、走らせる側でそのつど渡す形でも構いません。

CLAUDE_CODE_WEBFETCH_DEADLINE_MS=60000 claude -p "$(cat ./prompts/watch-release-notes.txt)"

内側の期限と、外側の上限

期限が付いたことで、WebFetch 一回あたりの最悪値は読めるようになりました。ただし、タスク全体の最悪値はまだ読めません。取得先の数だけ 60 秒が積み上がりますし、詰まる場所は WebFetch だけとも限らないからです。

そこで、走らせる側にもう一枚、上限を敷いております。

#!/usr/bin/env bash
set -uo pipefail
 
LOG="${HOME}/logs/watch-release-notes-$(date +%F).log"
mkdir -p "$(dirname "$LOG")"
 
# 内側: WebFetch 一回あたりの期限
export CLAUDE_CODE_WEBFETCH_DEADLINE_MS=60000
 
start=$(date +%s)
# 外側: タスク全体の上限。TERM で終わらなければ 30 秒後に KILL
timeout --signal=TERM --kill-after=30s 20m \
  claude -p "$(cat ./prompts/watch-release-notes.txt)" >> "$LOG" 2>&1
code=$?
elapsed=$(( $(date +%s) - start ))
 
case "$code" in
  0)   printf 'ok elapsed=%ss\n' "$elapsed" >> "$LOG" ;;
  124) printf 'CEILING 外側の上限に当たりました elapsed=%ss\n' "$elapsed" >> "$LOG" ;;
  *)   printf 'FAILED exit=%s elapsed=%ss\n' "$code" "$elapsed" >> "$LOG" ;;
esac
exit "$code"

外側の値は、内側の期限に取得先の数を掛けて、少し余裕を足した程度で足ります。20 分という数字自体に根拠はなく、私の巡回リストの長さから逆算しただけのものです。

なぜ二枚要るのかと言えば、内側は「この一回を諦める」ための仕組みで、外側は「今夜はもう終わりにする」ための仕組みだからです。役割が違いますので、片方で兼ねられません。待ち時間の上限は、道具の内側と実行の外側に一つずつ置きます。 この置き方にしてから、翌朝ログの末尾が空白のままということはなくなりました。

当たったことを、翌朝わかるようにしておく

期限を置いただけでは、まだ半分です。当たったことが記録に残らないと、取得できていないページがあることに気づけません。静かな失敗は、返ってこないより厄介なことがあります。

巡回リストの前さばきを、タスクの外側で済ませる形にしました。

#!/usr/bin/env bash
set -uo pipefail
 
SRC="./urls.txt"                       # 巡回したい URL を1行ずつ
TODAY="${HOME}/logs/urls-$(date +%F).txt"
REPORT="${HOME}/logs/probe-$(date +%F).tsv"
: > "$TODAY"; : > "$REPORT"
 
while read -r url; do
  [ -z "$url" ] && continue
  t0=$(date +%s)
  http=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 20 "$url") || http="000"
  printf '%s\t%s\t%ss\n' "$url" "$http" "$(( $(date +%s) - t0 ))" >> "$REPORT"
  [ "$http" = "200" ] && printf '%s\n' "$url" >> "$TODAY"
done < "$SRC"
 
# 200 を返した URL だけを本番のプロンプトへ渡します
echo "probe: $(wc -l < "$TODAY") / $(grep -cve '^$' "$SRC") 件が応答しました"

http=000 の行が、応答を返さなかった URL です。翌朝この 1 ファイルを見れば、昨夜どこが欠けたのかがひと目で分かります。取得先が固定の巡回では、この前さばきのほうが本体の調整より効きました。

キャッシュの持ち方と合わせて考えたい方は、調べ物タスクの WebFetch キャッシュ TTL を、自分の使い方に合わせて選ぶも併せてご覧ください。期限は一回の取得を諦める話で、TTL は取得そのものを減らす話ですので、両方を触ると効き方が分かりやすくなります。

今夜の巡回を回す前に、CLAUDE_CODE_WEBFETCH_DEADLINE_MS を一度だけ短めに置いて、翌朝ログの末尾を確かめていただければと思います。空白で終わっていないことが確認できれば、それだけで夜の見通しはずいぶん変わります。

夜のあいだ何かを走らせている方に、ひとつでも手がかりが渡れば嬉しく思います。ありがとうございました。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-08-18
調べ物タスクの WebFetch キャッシュ TTL を、自分の使い方に合わせて選ぶ
Claude Code の WebFetch には URL キャッシュの TTL 設定があります。同じページを何度も取りに行く調べ物タスクで、取得回数と情報の鮮度がどう入れ替わるのかを、観測用の小さなサーバと計算スクリプトで確かめながら決めていきます。
Claude Code2026-09-10
「Not signed in to the Cloud gateway」で全リクエストが止まる朝に、設定より先に版を見ます
Claude Code 2.1.265 でゲートウェイ・プロキシ構成が全リクエスト失敗した回帰を入口に、認証の入力面を一枚に並べて「設定と版のどちらが変わったか」を数秒で切り分ける小さな手順をまとめます。
Claude Code2026-09-05
拒否ルールが見ていたのはファイル名で、そこへ届く経路ではありませんでした
deny に書いた 1 行が、同じファイルへ届く別の書き方を素通りさせていました。経路を機械的に並べて、版を上げた日に効きを確かめる小さな検査表の作り方をお伝えします。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます