Extended thinking + tool use: signature-only thinking blocks permanently break --resume (400 cannot be modified)
What happened
On sessions that use extended thinking together with tool use, Claude Code persists thinking content blocks to the session transcript (~/.claude/projects/**/<session-id>.jsonl) with their signature intact but the thinking text field empty ("thinking": ""). I'll call these "hollow" thinking blocks.
On --resume, when Claude Code rebuilds the conversation from that transcript and has to replay such a block as part of the latest assistant message, it sends the hollow block to the API, which rejects the request:
API Error: 400 messages.N.content.M: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.
Every subsequent turn re-sends the same block, so the session becomes permanently unresumable — continue, a new prompt, anything 400s identically.
Version
Claude Code 2.1.156
Steps to reproduce
- Run a session with extended thinking enabled that does interleaved thinking + (ideally parallel) tool use.
- Have it end on / be interrupted at an assistant turn that contains a
thinkingblock followed bytool_use. claude --resume <session-id>-> 400 on the first turn, and on every turn after.
Evidence
Inspecting the transcript JSONL, the thinking blocks are stored as:
{"type": "thinking", "signature": "<long signature present>", "thinking": ""}
Signature kept, reasoning text empty. This appears for every thinking block (observed across hundreds of transcripts on this machine), independent of MCP servers or hooks — it reproduces with all hooks/MCP disabled, so it is not caused by any third-party hook modifying the transcript.
Impact
- A session that ends on a thinking + tool-use turn is permanently wedged on resume.
- Affects anyone running extended thinking + tools (a very common configuration).
Workaround
Strip the hollow thinking content blocks from the transcript (remove thinking-type blocks whose text is empty and re-link the parentUuid chain) before resuming.
Suggested fix
Either persist the full thinking text alongside the signature in the transcript, or omit/strip prior-turn thinking blocks when rebuilding history on resume rather than sending a signature-only block that necessarily fails the API's "must remain unmodified" check.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗