claude-code - 💡(How to fix) Fix Resuming an extended-thinking session fails permanently with 400 "thinking blocks cannot be modified" (transcript stores thinking text as empty but keeps signature) [2 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Resuming/continuing a session that used extended thinking together with tool calls can put the session into a permanently broken state. Every subsequent turn returns the same error:

API Error: 400 messages.1.content.5: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.

Once it starts, the session can never be continued again — continue, any new prompt, even a no-op, all return the identical 400.

Error Message

API Error: 400 messages.1.content.5: thinking or redacted_thinking blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.

Root Cause

Claude Code persists extended-thinking blocks to the session transcript (projects/<slug>/<id>.jsonl) with the thinking text emptied to "" but the signature field retained. A thinking content block on disk looks like:

{ "type": "thinking", "thinking": "", "signature": "<base64 signature, ~600–4000 chars>" }

When the session is rebuilt from this transcript (on resume/continue, and apparently on other history-reconstruction paths), Claude Code sends these blocks back to the API as { "type": "thinking", "thinking": "", "signature": "<original>" }. The API validates the signature against the thinking text; since the text is now empty but the signature was computed over the original non-empty text, validation fails → the 400 above.

Because the original thinking text is gone from disk, the request can never be reconstructed into a valid form — the session is permanently poisoned.

Fix Action

Fixed

Code Example

API Error: 400 messages.1.content.5: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.

---

{ "type": "thinking", "thinking": "", "signature": "<base64 signature, ~600–4000 chars>" }

---

$ jq -rc 'select(.type=="assistant")|.message.content[]?|select(.type=="thinking")|[(.thinking|length),(.signature|length)]|@tsv' broken.jsonl
0    3932
0    1196
0    1632
0    620
0    1172
RAW_BUFFERClick to expand / collapse

Environment

  • Claude Code: 2.1.153
  • OS: macOS (Darwin 25.3.0)
  • Auth: subscription, extended thinking enabled

Summary

Resuming/continuing a session that used extended thinking together with tool calls can put the session into a permanently broken state. Every subsequent turn returns the same error:

API Error: 400 messages.1.content.5: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.

Once it starts, the session can never be continued again — continue, any new prompt, even a no-op, all return the identical 400.

Root cause

Claude Code persists extended-thinking blocks to the session transcript (projects/<slug>/<id>.jsonl) with the thinking text emptied to "" but the signature field retained. A thinking content block on disk looks like:

{ "type": "thinking", "thinking": "", "signature": "<base64 signature, ~600–4000 chars>" }

When the session is rebuilt from this transcript (on resume/continue, and apparently on other history-reconstruction paths), Claude Code sends these blocks back to the API as { "type": "thinking", "thinking": "", "signature": "<original>" }. The API validates the signature against the thinking text; since the text is now empty but the signature was computed over the original non-empty text, validation fails → the 400 above.

Because the original thinking text is gone from disk, the request can never be reconstructed into a valid form — the session is permanently poisoned.

Evidence

In a broken session, every thinking block has empty text but a present signature (lengths shown — thinking-len, signature-len):

$ jq -rc 'select(.type=="assistant")|.message.content[]?|select(.type=="thinking")|[(.thinking|length),(.signature|length)]|@tsv' broken.jsonl
0    3932
0    1196
0    1632
0    620
0    1172

Line 1 of the broken transcript is {"type":"last-prompt","leafUuid":...}, indicating the session was resumed/forked.

This is not isolated: across many healthy sessions the trailing thinking block is also frequently stored empty-but-signed, so any such session becomes a landmine if it is later resumed.

Reproduction

  1. Start a session with extended thinking enabled.
  2. Do work that produces thinking blocks interleaved with tool calls.
  3. Exit, then resume the session (--resume / --continue / pick from history).
  4. Send any prompt → 400 "thinking blocks … cannot be modified", repeating on every subsequent turn.

Impact

  • Resumed extended-thinking + tool sessions can become permanently unusable.
  • The failure is silent until resume, so users lose the ability to continue long working sessions with no warning and no recovery path.

Suggested fix

When rebuilding the request from the transcript, Claude Code should never send a thinking block whose text was not preserved. Options:

  • Persist the full signed thinking text so the signed block round-trips intact; or
  • Drop thinking blocks entirely from reconstructed prior turns (the API permits omitting earlier-turn thinking) instead of sending thinking:"" + signature; or
  • Defensive guard: during request build, detect empty-text-with-signature thinking blocks and strip them before sending.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING