Mid-session model switch corrupts conversation when extended thinking is enabled (API 400: 'thinking blocks cannot be modified')
Summary
Switching models mid-session in Claude Code while extended thinking (alwaysThinkingEnabled: true) is on permanently corrupts the conversation. Every subsequent 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 triggers, the session is unrecoverable from inside the CLI — typing anything just re-ships the now-mixed-model history and re-fails.
Reproduction
~/.claude/settings.json:"alwaysThinkingEnabled": true.- Start a
claudesession on, say, Opus 4.7. - Run a handful of turns including tool calls (so several thinking blocks are produced and persisted).
/modelto a different model (e.g., Opus 4.8 — or any other model).- Continue the conversation. After a few turns the next API request 400s with the "thinking blocks cannot be modified" error, and stays broken on every retry.
Why this happens
Thinking blocks come back from the API with cryptographic signatures that are model-specific. They have to be returned verbatim on later turns. After a /model switch the persisted history still contains thinking blocks signed by the previous model; once a later turn re-ships one of those, the API refuses because the signature doesn't validate under the currently-selected model. The CLI happily accepts the model switch but doesn't reconcile the history, so the breakage is just delayed by however many turns it takes to re-hit a prior signed block.
Expected behavior
Any of:
- Warn / block on
/modelwhen there are signed thinking blocks in the history. Cheapest fix and prevents the failure mode. - Auto-purge prior-model thinking blocks from the persisted history on model switch, with a one-line notice ("prior reasoning context cleared for model switch"). The next turn proceeds without that context but the conversation isn't bricked.
- Repair tooling: a
/recoverorclaude session repair <sid>command that truncates the JSONL to the last single-model boundary and lets the user resume. Today this requires hand-editing the JSONL on disk, which is awful UX for a known failure mode.
Actual behavior
The CLI silently allows the switch, then 400s some number of turns later with no path to recover from the prompt. The only fixes are: (a) start a fresh session (lose all context), or (b) manually truncate the session JSONL to before the model switch and --resume on the original model.
Evidence from a real broken session
- 1053-line session JSONL at
~/.claude/projects/<sanitized-cwd>/<sid>.jsonl. - 290 assistant messages signed
model: claude-opus-4-7, then 14 signedmodel: claude-opus-4-8. - First 400 hit on
messages.113.content.4shortly after the model switch. - Every subsequent input (
continue, anything) re-shipped the same mixed history and re-hit the 400 identically./clearis the only working escape, which throws away the whole conversation.
Environment
- Claude Code (latest stable as of filing).
~/.claude/settings.json:"alwaysThinkingEnabled": true.- macOS, zsh.
Happy to attach a sanitized excerpt of the broken JSONL on request.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗