claude-code - 💡(How to fix) Fix Resumed extended-thinking sessions permanently 400 with "thinking blocks ... cannot be modified" (esp. after model change / with /goal)

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…

A long-running session that uses extended thinking + tool use can get into a state where every turn fails with:

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.

Once it starts, the session is permanently unusable — every subsequent user message 400s at the same messages.N.content.M index. The session can receive messages but can never respond.

Error Message

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.

Root Cause

A long-running session that uses extended thinking + tool use can get into a state where every turn fails with:

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.

Once it starts, the session is permanently unusable — every subsequent user message 400s at the same messages.N.content.M index. The session can receive messages but can never respond.

Fix Action

Fix / Workaround

Workarounds (none fully durable)

  • Strip thinking blocks from the .jsonl + resume (re-breaks as new blocks accumulate)
  • Lower effort / disable extended thinking (no blocks generated → nothing to corrupt) — most reliable
  • /goal clear to stop a looping goal that accelerates the failure

Code Example

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.
RAW_BUFFERClick to expand / collapse

Summary

A long-running session that uses extended thinking + tool use can get into a state where every turn fails with:

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.

Once it starts, the session is permanently unusable — every subsequent user message 400s at the same messages.N.content.M index. The session can receive messages but can never respond.

Environment

  • Claude Code 2.1.154–2.1.156 (reproduced on both macOS arm64 and Linux)
  • Models: Opus 4.8 (claude-opus-4-8) and 4.7; high/xhigh effort (extended thinking enabled)
  • Sessions launched with --channels, --permission-mode bypassPermissions, resumed with --resume <id>

Reproduction (reliable)

  1. Run a long session with extended thinking + tool use (e.g. a coding session at high effort, many tool calls).
  2. Resume it with --resume <id>especially after changing the model (e.g. relaunch the same conversation with --model opus[1m] when it previously ran on 4.7).
  3. On the next turn, the request 400s with the error above, and keeps 400ing on every subsequent message.
  • An active /goal loop makes it constant — the loop regenerates thinking every iteration and errors every few seconds.

Impact

  • The session is effectively bricked (can't respond at all).
  • During a fleet upgrade (resuming many sessions from 4.7 → 4.8), multiple sessions hit this independently.

Debugging findings

  • Stripping all thinking/redacted_thinking content blocks from the assistant messages in the session .jsonl, then resuming, temporarily fixes it (clean resume, no error). But new thinking blocks regenerate on subsequent turns and it re-breaks — the strip is not durable.
  • The error index (e.g. messages.47.content.26) stays constant even after the .jsonl is verified (JSON-parsed) to contain 0 thinking blocks. So the rejected blocks appear to come from somewhere other than the current on-disk conversation — prompt-cache replay, in-memory state, or a /goal loop's separate context — OR the persisted blocks have emptied text with a retained signature that fails validation on reload.
  • Occurs both across a model-version change and within continued use of a single model.
  • /rewind (restore conversation only) to before the offending turn also helps, but if a /goal was active it re-activates on resume and re-breaks.

Suspected cause

Thinking-block signatures (model-specific, computed over the original thinking text) are invalidated on persist/reload. The API requires the latest assistant turn's thinking blocks to be passed back byte-identical; the persisted/replayed version doesn't match (emptied text and/or model-version mismatch), so the API rejects it.

Workarounds (none fully durable)

  • Strip thinking blocks from the .jsonl + resume (re-breaks as new blocks accumulate)
  • Lower effort / disable extended thinking (no blocks generated → nothing to corrupt) — most reliable
  • /goal clear to stop a looping goal that accelerates the failure

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