Table of Contents
- 1. What This Error Is Actually Saying
- 2. Background: Extended Thinking and the "Signature" Mechanism
- 3. Why It Happens — 5 Root Causes
- 4. Three Fixes Right Now (for Claude Code Users)
- 5. For Developers: Prevent It in Your Own App (API/SDK)
- 6. Telling It Apart from Similar Errors
- 7. Recurrence-Prevention Checklist
- Summary
- FAQ
Have you been working in Claude Code when suddenly this error appears and the session stops responding entirely?
API Error: 400 messages.3.content.40: `thinking` or
`redacted_thinking` blocks in the latest assistant message
cannot be modified. These blocks must remain as they were
in the original response.
The nasty part: once it appears, every subsequent input triggers the same error. You type, you press Enter, same 400. The session enters a "stuck" state. This is a known bug with multiple open issues on Anthropic's official repository (#10199, #12225, #13012, #22278, #63147, and more).
Up front: the cause is "the extended-thinking blocks getting corrupted when the conversation history is re-sent." Thinking blocks carry a cryptographic signature, and the API validates the signature against the content byte-for-byte. When Claude Code rebuilds the history with a bug — e.g. emptying the thinking text but keeping the signature — the signature no longer matches and the API rejects it. The fastest escape is "press Esc twice and /rewind back to a checkpoint," or start a new session. This article covers the mechanism, the 5 root causes, 3 user-facing fixes, developer countermeasures, and recurrence prevention.
The full picture of the thinking-block error
— If the "signature" doesn't match, the API rejects the entire conversation
A known bug with multiple issues on Anthropic's official repo.
The essence: the API's strict rule that "thinking blocks must remain exactly as in the original response."
1. What This Error Is Actually Saying
In plain terms, the message says: "The thinking or redacted_thinking blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response."
That is, the API is telling you: "The 'thinking block' inside the conversation history you (the client) sent me differs from what I returned last time. It's been modified. So I won't accept it." The Claude API assumes you "include the previous response in the history and send it back unchanged" in multi-turn conversations — and the thinking block in particular carries a strict "do not change a single character" constraint. messages.3.content.40 is positional info: "the 41st content block of the 4th message" is where the problem is.
The important point: in most cases this is NOT a mistake in your code or prompt. The main cause is a bug in how Claude Code rebuilds the conversation history (the session JSONL), corrupting the thinking blocks. So there's no need to agonize over "am I using it wrong?" — it's a known bug with workarounds.
2. Background: Extended Thinking and the "Signature" Mechanism
Why is the thinking block alone this strict? The reason lies in how extended thinking works.
When Claude responds with extended thinking enabled, it generates a "thinking block" before the answer. This is Claude's intermediate reasoning — the internal "how it thought" that raises final-answer quality. This block is assigned a cryptographic signature — something like a digital signature guaranteeing "this thinking content was genuinely generated by Claude and has not been altered."
In multi-turn conversations and tool-use loops, the entire prior exchange is sent back to the API each time. The thinking blocks must be sent too, but the signature is computed over the "entire original thinking text" — so if the text changes even by one character, signature validation fails. For security, the API rejects thinking blocks whose signature doesn't match. That's the essence of the 400 error.
Why the signature exists
Preventing modification of thinking blocks blocks prompt injection and thought spoofing. It's a security mechanism protecting the fact that "Claude actually thought this" — the strictness has a reason.
3. Why It Happens — 5 Root Causes
The concrete scenarios for signature mismatch sort into five — synthesized from Anthropic's official issues and community reports.
Five root causes of signature mismatch
The common thread: if a thinking block differs from the original by even one byte, you always get a 400.
Causes 1–4 are Claude Code / proxy bugs; cause 5 is a DIY implementation issue.
4. Three Fixes Right Now (for Claude Code Users)
When your session is stuck, try three methods in order of recovery speed.
Three fixes by recovery speed
/rewind. Step back to the checkpoint before the corrupted turn. The best move — recovers while preserving context./clear or start a fresh session. The most reliable, but loses context. Note/commit important work first.
Try FIX 1 (Esc×2 / rewind) first. If that fails, FIX 2. If you must keep context, FIX 3.
And always update Claude Code to the latest version (Anthropic is fixing this progressively).
Note on FIX 3: the community has published a "Claude Code thinking blocks fix" tool (e.g. miteshashar/claude-code-thinking-blocks-fix on GitHub). It removes all thinking content blocks from the session JSONL, eradicating the signature problem while keeping conversation history. It's worth adopting if you hit this often or use long sessions heavily. But it's an unofficial tool, so use at your own risk — back up the JSONL before running it.
The most important permanent fix is "keep Claude Code on the latest version." Run claude update or follow the official update steps. Anthropic is progressively shipping a "defensive guard that detects empty-text-plus-signature thinking blocks and strips them before sending" for this series of bugs (#10199, #12225, #63147, etc.). Older versions hit it more often.
5. For Developers: Prevent It in Your Own App (API/SDK)
If you build an app hitting the Claude API/SDK yourself (extended thinking + tool use), you'll hit the same error in your own implementation. Three principles prevent it.
// BAD: deleting/altering thinking blocks before sending back
const history = previousMessages.map(m => ({
...m,
content: m.content.filter(b => b.type !== 'thinking') // mismatches signature
}));
// GOOD pattern 1: keep thinking blocks "exactly as-is"
// Push the assistant message from the API into history untouched
messages.push(assistantMessageFromApi); // keep the signature intact
// GOOD pattern 2: "fully drop" thinking from past turns
// Don't send empty text + signature; omit the block entirely
const clean = previousMessages.map(m => {
if (m.role !== 'assistant') return m;
return {
...m,
content: m.content.filter(b =>
b.type !== 'thinking' && b.type !== 'redacted_thinking'
),
};
});
// NOTE: do NOT drop them from the "latest" assistant message (during tool use)
The three principles: ① Fully preserve the signed thinking text and round-trip it intact. ② If you won't send past-turn thinking, remove the whole block (empty-text-plus-signature is the worst case). ③ Add a defensive guard at request-build time that detects "empty text but has a signature" thinking blocks and strips them.
The iron rule for tool-use loops
In extended-thinking + tool-use loops (tool_use → tool_result), never alter the thinking block of the "latest" assistant message. The next request returning tool_result must include the preceding thinking + tool_use exactly as-is. If you use Claude Agent SDK or Vercel AI SDK, verify the library handles this correctly.
6. Telling It Apart from Similar Errors
There are several thinking-related 400 errors, easy to confuse. Distinguish the three main ones.
| Error message | Meaning | Main fix |
|---|---|---|
| thinking blocks ... cannot be modified | This article's subject. Signature and content mismatch | /rewind, new session, update to latest |
| Invalid signature in thinking block | The signature itself is invalid (often proxy alteration) | Review proxy config, connect to API directly |
| The final block in an assistant message cannot be thinking | The assistant message ends with thinking (it needs text or tool_use at the end) | Fix message structure, update SDK |
The shared root cause is "not handling extended-thinking blocks correctly." For Claude Code users, most resolve with /rewind + latest-version update. For DIY apps, you need to review the message structure and library implementation. If you go through a proxy (CLIProxyAPI, various gateways), first suspect that the proxy is altering the thinking.
7. Recurrence-Prevention Checklist
A practical checklist to prevent frequent recurrence.
Claude Code users: ① Keep it on the latest version with claude update (the biggest preventive). ② Reset very long sessions periodically with /clear (reduces interleaving risk). ③ Commit to git frequently for important work (recoverable even if stuck). ④ Consider a JSONL-repair tool if it recurs often. ⑤ Report reproductions to Anthropic's official issues (speeds up fixes).
API/SDK developers: ① Push assistant messages into history without altering the API response. ② If dropping past thinking, remove the whole block (no empty-text-plus-signature). ③ Add a defensive guard at request-build (detect empty-text-plus-signature → strip). ④ Use the latest official SDK and minimize custom message reshaping. ⑤ If behind a proxy, verify thinking transparency.
Summary
Claude Code's "thinking blocks ... cannot be modified" 400 error happens when extended-thinking blocks get corrupted on history re-send and the cryptographic signature no longer matches the content. It's a known bug with multiple issues on Anthropic's official repo, and in most cases it's not your fault. The five causes: session-resume bug (most common), streaming interleaving, repair logic going rogue, third-party proxies, and history modification in your own app.
For Claude Code users, the fastest recovery is ① press Esc×2 / /rewind back to a checkpoint; if that fails, ② a new session (/clear); to preserve context, ③ a JSONL-repair tool. The most important permanent fix is "update Claude Code to the latest version" — Anthropic is progressively shipping a defensive guard. API/SDK developers should follow the three principles: round-trip thinking blocks as-is / fully remove them if dropping / add a defensive guard.
Related: What Is Claude Agent SDK, Vercel AI SDK complete guide, What Is Cursor, Claude Code/Cursor deploy workflow.
FAQ
Q. Is this error a mistake in my prompt or code?
A. In most cases, no. If it appears during Claude Code use, it's almost certainly a known bug on the Claude Code side (a session-history rebuild defect). Multiple issues are open on Anthropic's official repo and fixes are in progress. No need to blame yourself. Only for DIY apps (hitting the API directly) do you need to review your implementation.
Q. /rewind doesn't fix it. Now what?
A. Starting a new session (/clear) is the most reliable. You lose context but escape the stuck state for sure. Stash important work via git commit or notes first. If it recurs, update Claude Code to the latest version; if it still happens, consider a JSONL-repair tool.
Q. Can I avoid it by turning off extended thinking?
A. Technically yes, but extended thinking significantly improves accuracy on complex tasks, so turning it off isn't recommended. First handle it with latest-version update + /rewind, and only consider this as a last resort in special environments (e.g. behind a proxy) where it still recurs.
Q. Is the JSONL-repair tool safe?
A. It's unofficial, so use at your own risk. Always back up the session JSONL before using it. The mechanism is "remove all thinking content blocks while keeping conversation history," which is safe in principle — but the official fix (latest-version update) remains the real solution.
Q. In my own app, combining tool use with thinking triggers this error.
A. The cause is "you're altering the thinking block of the latest assistant message." The next request returning tool_result must include the preceding thinking + tool_use blocks exactly as the API returned them (with signature). If you drop past-turn thinking, remove the whole block (no empty-text-plus-signature). The latest official SDK handles most of this automatically.