0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code が API 400 で詰まる時、 cache_control 空テキストブロックの根本原因と復旧

0
Last updated at Posted at 2026-05-04

2026 年 4-5 月の Claude Code の自動運用の中で、 短いセッションでも突然 400 エラーで動かなくなる事故が複数回起きた。 GitHub Issue を遡ると同じ根本原因 (cache_control が空テキストブロックに付いている状態) で 12 本以上のスレッドが立っていた。 個別の報告は散発的だが、 1 つの原因にまとまっている。

公式の更新の通知には記載が無いため、 利用者の側で発見して、 利用者の側で復旧する必要がある型の不具合。 この記事は実際の復旧の手順と、 5 つの予防の指針をまとめる。

何が起きるか

短いセッションでも突然、API から 400 エラーが返り続けて作業が止まる。代表的なメッセージは次の 3 つで、順番にこの形で出ることが多い。

messages.N.content.M.text: cache_control cannot be set for empty text blocks
messages: text content blocks must be non-empty

「Try again」も claude --resume も同じエラーで止まる。新しいセッションを始めると直るが、それまでの文脈は捨てることになる。

なぜ詰まるか

会話履歴のどこかの content block が text: "" のまま cache_control: { type: "ephemeral" } を付けた状態で残り、API がそれを拒否する。一度この壊れたブロックが履歴に入ると、再送のたびに同じブロックが含まれるので、resume も Try again も同じ理由で落ちる。

「短いセッションだから長文ではない」と感じても、ツールを 1 回使うごとに assistant tool_useuser tool_result の 2 メッセージが追加される。ツール多用のセッションなら数ターンで messages[48] 程度まですぐ伸びる。

どんなときに発生しているか (2026 年 4-5 月の集積から)

  • 画像をキャプションなしで貼り付けた直後
  • ストリームの待機タイムアウト後の自動再送
  • AskUserQuestion の回答が空のまま送られたとき
  • セッション再開直後に履歴が壊れていたとき

GitHub Issue では同じ根本原因で別々のスレッドが 12 本以上立っている。本ガイドの公開前に各スレッドの本文を確認し、エラー文言と再現手順が一致するものだけを残した: #55369 / #55156 / #55302 / #55283 / #55118 / #54988 / #54421 / #54314 / #53632 / #50738 / #50681 / #50010 など。

壊れた行の見え方

JSONL の 1 行は 1 つのやり取りに対応し、 配列の中に複数の小さな塊が入る。 詰まりを起こす典型は、 中身の文字が空のまま、 印だけが付いている状態である。 API はそれを拒む。

具体的には、配列の中に次のような形のブロックが残っている。

{"type":"text","text":"","cache_control":{"type":"ephemeral"}}

最初の発見の手段は、 該当のファイルに対して以下を流して、 空の塊が何件あるかの大まかな見当を付けることである。

grep -c '"text":""' <session>.jsonl

0 件でも、 印のキーごと欠けた亜種で詰まっている可能性があるので、 0 件のときも次の節の復旧手順に進む。

現場での復旧手順

セッションは JSONL 形式で保存されているので、壊れたブロックを取り除けば文脈ごと復活できる。

  1. 該当プロジェクトの session ファイルを探す
    • Linux/macOS: ~/.claude/projects/-<sanitized-cwd>/<session-id>.jsonl
    • Windows: %USERPROFILE%\.claude\projects\-<sanitized-cwd>\<session-id>.jsonl
  2. 元ファイルを別名で必ず先に保全しておく (cp.bak を取る)
  3. 空テキストブロックを除去するスクリプトを通す
  4. 出力された .fixed.jsonl で元ファイルを置き換えて claude --resume
  5. 念のため、 置き換え後のファイルに対して再度 grep で空の塊を数え、 0 件になっていることを確かめてから本格的に再開する
import json, sys, pathlib

src = pathlib.Path(sys.argv[1])
dst = src.with_suffix('.fixed.jsonl')

with src.open(encoding='utf-8') as f, dst.open('w', encoding='utf-8') as g:
    for line in f:
        d = json.loads(line)
        msg = d.get('message')
        if isinstance(msg, dict) and isinstance(msg.get('content'), list):
            msg['content'] = [
                b for b in msg['content']
                if not (isinstance(b, dict) and b.get('type') == 'text' and not b.get('text'))
            ]
            if not msg['content']:
                continue  # 空になったメッセージは行ごと捨てる
        g.write(json.dumps(d, ensure_ascii=False) + '\n')

print(f'Wrote {dst}')

復旧スクリプトでも直らない時

スクリプトを通したあとでも 400 が再発する時は、 空テキストブロックではなく別の壊れ方が混ざっている可能性がある (画像の塊が壊れている、 道具の呼び出しと結果の対が崩れている、 など)。 その場合は、 文脈の損失を最小にする手順として次の 2 段に分けて対処する。

  1. 詰まったやり取りの直近の進行を、 別の場所 (mission.md や引き継ぎメモ) に手で抜き書きする
  2. 新しいやり取りを始め、 1 で抜き書きした内容を最初の 1 通として貼り付けて再開する

直近の本文だけを抜き出すには、 jq を使った 1 行の絞り込みが早い。

jq -r '.message.content[]?.text // empty' <session>.jsonl | tail -200

大半の文脈はこの出力から手で復元できる。

予防

  • 画像をキャプションなしで貼らない。一文字でも文字を添える
  • 「Stream idle timeout — partial response received」が出たときは、同じターンを再送せず、新しいプロンプトから始める
  • 長時間セッションの再開地点は、履歴ではなく再開専用ファイル (mission.md など) に集約する。履歴破損で文脈を失っても、再開ファイルで復帰できる体制を作っておく

月次の安全チェック追加項目

  • 重要セッションを始める前に session ファイルの場所を確認しておく
  • セッションが API 400 で詰まったら、まず claude --resume を試す前に session ファイルをコピーしておく
  • 長時間セッションは、内容が膨らむ前に区切ってコミット・記録する

参考

  • 大元のエラーは Anthropic API 側のバリデーション (cache_control を空テキストブロックには設定できない) なので、Claude Code 側で送信前に空ブロックを落とすかキャッシュ印を外せば再発しなくなる
  • 復旧スクリプトの肝は「空 text block を消す」ことと「全部消えたメッセージは丸ごと捨てる」こと。この 2 つで 400 が止まる

同じ時期に発生した別の根本原因の事故事例 (cache_creation の急増、 子エージェントが親の会話履歴を漏らす、 子エージェントの作業領域の境界の不在、 自動の運用での利用枠の焼き) は、 月次でまとめた解説の取り組みを始めた。 この記事の本文は 5 月号の事故事例の章の全文の抜粋で、 5/5 配信予定。
販売ページ: https://note.com/yurukusa/n/n5f83f1f464d1


📚 関連の参考資料 (2026年5月28日追加)

本記事の内容と関連する整理を、 公開済の素材で articulate しています。

  • 6月15日に予定された課金分離(当日に一時停止・再実施に備える)の判定の枠組み: Migration Playbook v2 (Gumroad、 $19) ——14日後の決定の整理、 9集積の文脈、 130件の claim-verify divergence の事例。 60秒の購入判定の道具で事前判定が可能

  • 月刊の継続レポート(note メンバーシップ): Claude Code 事故まとめ(無料・月次) ——毎月、その月に実際に起きた事故と仕様変更を実機で検証してまとめます。この cache_control の事故も2026年6月号で深掘りしています。今月の事故のまとめ・安全チェックリスト・コピペできる hook と設定例を月次で更新。断片的な情報を自分で集める代わりに、検証済みの月次の更新で最新の事故に追従できます。

  • 9集積の枠組みの英語の長編 Gist: The 9-Cluster Framework: Mapping the Structural Failure Surface of Claude Code Operator Defense ——約3,300単語、 全件の集積の mechanism / symptom family / defense path の整理。 cluster 9 (Usage Policy classifier over-trigger on Opus、 25+件の起票) の対話型診断道具: 4問の質問→推奨経路の道具

  • 約800件の MIT ライセンスの hook: cc-safe-setup (GitHub) ——9集積に対応する hook を整備した累計


Claude Code の運用・安全・費用の検証記事は、これからも続けて公開します。note のゆるくさ をフォローしておくと、新しい記事を公開したときに通知が届きます(無料)。


この cache_control の詰まりは、Claude Code で「エラーも警告も出ないのに、セッションが静かに壊れて先へ進めなくなる」型の事故の一つです。同じ「黙って詰まる・消える」型は、自動圧縮で長い履歴が飛ぶ、worktree の編集が本流に着地する、フォルダ移動で会話の履歴が消える、など他にもあります。こうした取り返しのつかない事故を、症状から該当章へ直接飛べる早見表つきで、設定での先回りまでまとめたのが Claude Code 事故防止ハンドブック(第3章まで無料・以降も毎月更新)です。この cache_control の詰まりも、巻頭の早見表から第22章(沈黙のデータ消失)へたどれます。

まず、自分のトークン消費がどこで膨らんでいるかは、無料のトークン消費の詳しい診断で確かめられます。/cost の出力を貼るだけで、キャッシュの効き方と CLAUDE.md の常駐コストまで内訳が出ます。ブラウザの中だけで動くので、貼った内容はどこにも送信されません。自分の浪費を確かめてから、下の本で全手順を読むのが早いです。

トークンの消費がどこで膨らんでいるかを実機のログから切り分け、設定と文脈の管理とワークフローの設計で半分まで減らす全手順は、Claude Code のトークン消費を半分にする本(¥2,500・第1章まで無料の試し読み)にまとめています。


ほかにも、800時間の運用データから、トークン消費の削減・複数ベンダー(Claude / Codex / Gemini / Copilot)の並行運用・サブエージェントの沈黙の失敗対策など、テーマ別の手引きを公開しています。気になる人は著者の本の一覧から、価格と評価を見て選べます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?