claude -p が結果を出した後に返ってこない — 2.1.163 のハング修正と、無人 cron に今日入れる5つの設定


朝のジョブが、結果ログだけ吐いて返ってこない。claude -p は最終結果を出力しているのに、プロセスが終わらない。終了コードが立たないから cron からは「成功」とも「失敗」とも見えず、次回の起動が前のインスタンスと重なるか、上限を切っていなければスロットを朝まで占有する。失敗より、この「黙って終わらない」状態のほうが無人運用ではずっと厄介だ。

Claude Code 2.1.163 で、この症状の一種が時間境界化された。バックグラウンドで起動したコマンドが終わらないと claude -p が最終結果後に永久ハングしていた不具合が直り、stdin が閉じたあと約5秒でバックグラウンドシェルを停止してプロセスが抜けるようになった。この記事は、その修正が「何を直して何を直さないか」を仕分けし、今日 cron 構成に当てられる設定を具体的に並べる。

なお、この挙動は2026年6月時点で公式の headless ドキュメントには記載されていない(GitHub Issue #65498「Headless docs omit claude -p background-shell cleanup after final result」)。changelog を追っていないと素通りしやすい変更なので、まとめておく。

一次資料(逐語)

changelog の該当エントリ(Claude Code 2.1.163)はこう書かれている。手元の claude --version で版を照合できる。

Fixed claude -p hanging forever after its final result when a backgrounded
command never exits — background shells are now stopped ~5s after the result
once stdin closes

要点は2つ。(1) 契機は「stdin が閉じたこと」、(2) 猶予は「結果の約5秒後」。つまり -p に標準入力を渡し切って閉じれば、終わらないバックグラウンドシェルがいても5秒で畳まれ、プロセスが返る。「いつか終わるかもしれない」が「5秒後には必ず畳む」に変わった、というのがこの修正の本質だ。無限のハングは検知も回収もできないが、有限のタイムアウトなら検知して記録してリトライに回せる。

直る / 直らない 早見表

最初に押さえるべきは、無人 cron が「黙って止まる」理由は一種類ではない、ということ。今回の修正はそのうち一つにだけ効く。

症状(止まり方)この修正で改善効く版 / 取るべき対策
最終結果後、終わらないバックグラウンドシェルで claude -p が永久ハング2.1.163(stdin クローズ後 約5秒で停止)
リモート MCP ツール呼び出しが5分間無応答でブロック2.1.187(中断してエラー化。CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT で調整)
アイドルなバックグラウンドシェルがメモリを食い続ける2.1.193(自動回収。CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP=1 で無効化可)
多数のジョブを一気に並列起動して API がレート制限(429)を返す×別問題。同時実行数を絞る/バッチを分割する
数時間かかる処理が、利用枠の上限に達して途中で止まる×別問題。上限リセット直後に開始/処理を短く分割
クライアントを再起動したら走っていたジョブごと消える×別問題。完了分を記録しておき、残りだけ再投入する

右3行(×)は今回の修正のスコープ外だ。レート制限はサービス側のポリシーで、プロセスの終わり方を直しても変わらない。利用枠の上限や再起動耐性も別レイヤーの話で、ここを「2.1.163 で全部解決した」と思って無対策で大量並列を流すと、別の死因で同じように止まる。修正が時間境界化したのは、あくまで「最終結果後のバックグラウンドシェル居座り」という一つの死因だけだ。

同じ方向の修正クラスタ

2.1.163 単体で見ると「たまたま一つ直った」ように見えるが、実際には「終わらない非同期処理に上限を引く」修正がこの前後で続いている。

修正内容オーバーライド環境変数
2.1.163claude -p の最終結果後ハングを stdin クローズ後 約5秒で停止(固定・なし)
2.1.187リモート MCP ツールの5分無応答を中断してエラー化CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT
2.1.193アイドルなバックグラウンドシェルのメモリ圧迫を自動回収CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP=1(無効化)

関連して、Vertex / Foundry 経由でストリームが止まったときに既定5分でアボートする idle timeout も復活している(API_FORCE_IDLE_TIMEOUT=0 でオプトアウト)。いずれも「止まり方に上限を持たせる」という同じ方向の変更だ。一方が固定値、もう一方は環境変数で選べる、という差はあるが、上限を設計の対象として手元に残す、という前提を共有している。

今日、無人 cron に当てる5項目

自分の構成に当てはまるものだけ拾えばいい。

  1. 版を上げる。 claude --version で 2.1.163 以上を確認する。未満なら npm i -g @anthropic-ai/claude-code で更新。これをやらないと以下は効かない。
  2. cron / タスクの実行時間に上限を入れる。 ハングが5秒で畳まれてプロセスは返るようになったので、上限は「無限」ではなく「想定処理時間 + バッファ」でよい。純粋にビジネスロジック上の最大実行時間として設計できる。
  3. リモート MCP を使うなら応答待ち上限を確認する。 既定は5分(2.1.187)。長い処理を呼ぶ場合は CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT で調整、逆に早く諦めさせたいなら短くする。
  4. Vertex / Foundry 経由で API を叩くなら idle timeout の扱いを決める。 既定の5分アボートを切りたい場合だけ API_FORCE_IDLE_TIMEOUT=0。理由なく切らない。
  5. 大量並列・長時間処理は別対策を併用する。 早見表の右3行はこの修正では直らない。並列を絞る、バッチを分割する、完了分を記録して残りだけ再投入する、という従来の備えはそのまま要る。

cron 構成の before / after

「プロセスが返ってこない」前提で実行時間上限を無限にしていたなら、ここを見直す。

Windows タスクスケジューラ(タスク XML):

<!-- before: 上限なし(ハングするとスロットを占有し続ける) -->
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>

<!-- after: 想定処理時間 + バッファ(例: 2時間) -->
<ExecutionTimeLimit>PT2H</ExecutionTimeLimit>

Linux cron + timeout コマンド:

# before: タイムアウトなし
0 7 * * * claude --print "/daily-job"

# after: timeout で外側からも上限をかける(例: 7200秒)
0 7 * * * timeout 7200 claude --print "/daily-job"

2.1.163 でプロセス自体は5秒で返るようになったので、これらの外側タイムアウトは「保険」ではなく「処理の最大許容時間」という意味を持つようになる。境界が引けて初めて、上限の値そのものが設計の対象になる。

まとめ

無人運用の信頼性は、機能の多さではなく、悪い状態に必ず終わりが来るかで決まる。永久ハングは観測も回収もできないが、タイムアウトは観測でき、観測できれば設計できる。2.1.163 が効いたのは賢さではなく、終わらない処理に境界を一本引いたことだった。同じ問いを自分の運用全体に当てたい——各ジョブに上限はあるか、上限が切れたとき何が起きると決めてあるか、その上限は黙って無効化されていないか。沈黙を恐れて張りつくのではなく、沈黙に必ず期限を与えて手を離す。

関連書籍 (Amazon)

  • SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム(Betsy Beyer 他、玉川竜司 訳)— タイムアウトやエラーバジェットなど、信頼性を「数値の境界」で扱う発想の原典。無人運用の上限設計を考える土台になる。https://www.amazon.co.jp/dp/4873117917?tag=swipegadgetjp-22
  • サイトリライアビリティワークブック ―SREの実践方法(Betsy Beyer 他、玉川竜司 他 訳)— 上の実践編。SLO・アラート・自動回復の具体例が多く、cron の部分失敗をどう拾い直すかの設計に直接効く。https://www.amazon.co.jp/dp/4873119138?tag=swipegadgetjp-22
  • Release It! 本番用ソフトウェア製品の設計とデプロイのために(Michael T. Nygard、でびあんぐる 訳)— タイムアウト欠如・サーキットブレーカーなど「止まり方」を設計するアンチパターン集。永久ハングが何を壊すかを具体的に教えてくれる。https://www.amazon.co.jp/dp/4274067491?tag=swipegadgetjp-22

一次資料

  • Claude Code changelog(Claude Code 公式。2.1.163: claude -p がバックグラウンド命令の未終了で最終結果後に永久ハングする不具合の修正=stdin クローズ後 約5秒でバックグラウンドシェルを停止 / 2.1.187: 5分間応答が返らない MCP ツール呼び出しを中断してエラー化、CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT で上限変更可 / 2.1.193: アイドル背景シェルのメモリ圧迫を自動回収、CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP=1 で無効化可): https://code.claude.com/docs/en/changelog
  • GitHub Issue #65498(公式 headless ドキュメントが claude -p の背景シェルクリーンアップを未記載である件): https://github.com/anthropics/claude-code/issues/65498