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.
If the signature on a thinking block you send back fails verification, you may see the error below instead. Both come from the same thing: the thinking block is no longer exactly as it was in the original response:
API Error: 400 messages.1.content.0:
invalid `signature` in `thinking` block
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 checks that the thinking blocks you send back are unchanged from the original response. When a bug in how Claude Code rebuilds the history makes a block differ from the original, 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, and the thinking blocks must be sent too. According to the official documentation, the signature carries an encrypted copy of the full thinking: the API uses it to verify that a returned thinking block was generated by Claude, and the server decrypts it to reconstruct the original thinking. The thinking text you can see is a summary, and on newer models the default (display: "omitted") leaves it empty. The signature value is the same whichever display setting you use, and any text you put into the thinking field of an omitted block is ignored. That is why the docs ask you to pass thinking blocks back exactly as you received them, unmodified. When the signature is missing or corrupted, or the block no longer matches the original response, the API rejects that thinking block. 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. The Claude Code changelog lists fix after fix in this family: interleaved streaming with concurrent agents (2.1.47), proactively stripping stale signatures left after a model or login switch (2.1.152), thinking blocks being modified with Opus 4.8 (2.1.156), and dropping thinking blocks and retrying once after a redacted_thinking error (2.1.282). Even so, #63147 was reported to still reproduce on 2.1.157 and remains open as of October 4, 2026. Older versions are missing more of these fixes.
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. The official documentation boils prevention down to one rule: send each assistant turn back exactly as the API returned it, thinking blocks included, and only append new messages at the end.
// BAD 1: rebuilding the assistant message from picked block types
const rebuilt = {
role: 'assistant',
content: [
...response.content.filter(b => b.type === 'thinking'), // drops redacted_thinking
...response.content.filter(b => b.type === 'tool_use'),
],
};
// BAD 2: deleting thinking blocks that have empty text and only a signature
// On newer models this is the normal shape (display defaults to "omitted")
// GOOD: push the assistant message from the API untouched, then append
messages.push({ role: 'assistant', content: response.content }); // thinking, redacted_thinking and signatures included
messages.push({ role: 'user', content: [toolResult] }); // new messages go at the end only
① A thinking block with empty text and only a signature is normal. On newer models, display defaults to "omitted": the full thinking is encrypted inside signature, and the thinking field comes back empty. Send it back as-is — don't fill it in or strip it (any text you put in the thinking field of an omitted block is ignored).
② Don't prune past-turn thinking yourself. If you pass every block back, the API keeps what each model needs, drops the rest automatically, and bills input only for the blocks actually shown to Claude. Omitting prior turns' thinking is allowed outside tool use, but on newer models a thinking block stays valid only while the system prompt, tools and earlier messages are unchanged — editing a middle turn or dropping only some blocks invalidates every later thinking block and returns a 400 (Invalid signature in thinking block; enforced, for example, on accounts created on or after August 31, 2026). To slim the history, leave it to server-side context editing (thinking-block clearing) or compaction.
③ Treat redacted_thinking the same way. A filter that keeps or removes only type === 'thinking' silently loses redacted_thinking. The official troubleshooting guide names the most common causes of this error: filtering blocks by type and dropping redacted_thinking, and rebuilding the assistant message instead of echoing it (Thinking, Thinking troubleshooting, as of October 4, 2026).
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 | Signature verification failed: the thinking block was altered or corrupted after the original response (by history reconstruction, or by a proxy rewriting the content) | /rewind, new session, update to latest; if you go through a proxy, review its config too |
| 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 (thinking, redacted_thinking and signatures included). ② Keep the history append-only: don't edit middle turns or drop only some blocks (leave trimming to server-side context editing or compaction). ③ Don't strip thinking blocks that have empty text and a signature (the default shape on newer models). ④ 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 no longer match the original response. 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 / history-rebuild bug, 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" — the changelog shows fix after fix for this family. API/SDK developers should send each assistant turn back exactly as returned, thinking blocks included / keep the history append-only / leave empty-text-plus-signature blocks alone.
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). You don't need to prune past-turn thinking yourself; on newer models, dropping it from only some turns invalidates the later thinking blocks. A block with empty text and only a signature is the normal shape on newer models, so send it back unchanged. The latest official SDK handles most of this automatically.
Related Claude Code errors: Claude Code errors reference, "court" / leaked invoke tags, "Prompt is too long".
Related: Claude adaptive thinking explained.