Claude "Invalid signature in thinking block" (400): Causes and Fixes

Wokey Team · 2026-10-30

Short answer: Invalid `signature` in `thinking` block is a 400 from Claude saying that a thinking block in your conversation history failed verification. Either the signature isn't one Claude issued (empty, cut short, changed, or created by another provider), or, on the newest models, something earlier in the conversation changed after the block was written. Switching Claude accounts or API keys doesn't cause it. Retrying the same request won't clear it: remove the thinking blocks from the history, or start a new conversation.

Two versions of the message

Message What failed
messages.N.content.N: Invalid `signature` in `thinking` block The signature itself didn't verify: it was empty, truncated, altered, or never came from Claude
…Invalid `signature` in `thinking` block. The block is bound to a different conversation. Remove the block, or set `thinking.block_binding.prefix_mismatch_behavior` to "drop_block". The prefix check: the system prompt, tools or an earlier message changed after the block was produced

The prefix check applies to Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5. Anthropic enforces it by default for accounts created on or after August 31, 2026, and for any request that sets thinking.block_binding. The full API response looks like this:

{"type":"error","error":{"type":"invalid_request_error","message":"messages.1.content.0: Invalid `signature` in `thinking` block"},"request_id":"req_011C..."}

Two related errors come from the same history check: Invalid `data` in `redacted_thinking` block, and `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified, which means the thinking text itself was edited.

In Claude Code

Claude Code shows it as API Error: 400 … Invalid `signature` in `thinking` block. Recent versions recognize the error, drop the earlier thinking blocks and retry, so the session usually continues without you seeing anything. If every turn fails with it, update first (claude update). Older releases, such as the 2.0 series, don't recover on their own. If it persists after updating, run /rewind to go back to a turn before the problem, or /clear to start fresh.

Cause 1: history from another provider

This is the most common cause for anyone who uses more than one provider in the same conversation. Several non-Anthropic models offer an Anthropic-compatible API and return thinking blocks of their own. Their signature field holds that provider's own string, or nothing at all. Claude can't verify either one.

So the error appears when a conversation starts on another model and then moves to Claude:

  • switching providers mid-session with a config switcher or by editing ANTHROPIC_BASE_URL;
  • using /model on a gateway to go from a non-Claude model, such as DeepSeek, to a Claude model in the same session;
  • resuming a session that was started against a different provider.

This happens on Wokey too. Wokey forwards thinking blocks exactly as it receives them. It neither rewrites nor strips them, so a block produced by DeepSeek earlier in the conversation still carries DeepSeek's signature when the conversation reaches Claude.

Switching between Claude models, or between Claude accounts, is different. When a Claude model can't use a block written by another Claude model, or a Sonnet 5.5 or Haiku 5.5 block written by another account, the API drops the block silently and the request succeeds.

Cause 2: the client stored the block incorrectly

The API needs each assistant turn back exactly as it was returned. Common ways a client breaks that:

  • saving the thinking text but not the signature;
  • collecting a streamed response without appending the signature_delta events;
  • trimming, truncating or re-encoding the signature string;
  • copying the same thinking block into several messages.

Opus 5.5, Sonnet 5.5, Haiku 5.5 and Fable 5.1 return thinking blocks with an empty thinking field by default. The signature carries the reasoning, so the block is still complete and must be sent back as it is.

Cause 3: the conversation changed (prefix check)

The "bound to a different conversation" version means the history before the block no longer matches. Common causes: editing, reordering or deleting an earlier turn, rebuilding the system prompt or tools array each turn, removing a reminder injected earlier, or client-side compaction that keeps recent turns together with their thinking.

How to fix it in your own code

Send assistant turns back verbatim. Keep the whole content array, thinking blocks and signatures included, rather than rebuilding it from text.

When the history came from another provider, strip thinking before sending it to Claude. Remove every thinking and redacted_thinking block and keep the other blocks in each turn:

def strip_thinking(messages):
    cleaned = []
    for message in messages:
        content = message["content"]
        if message["role"] == "assistant" and isinstance(content, list):
            content = [b for b in content if b.get("type") not in ("thinking", "redacted_thinking")]
        cleaned.append({**message, "content": content})
    return cleaned

For the prefix-check version, keep the history append-only. Add new instructions as a new message instead of editing system or tools. To keep a request going without the stale reasoning, send the thinking-binding-controls-2026-08-01 beta header and set thinking.block_binding.prefix_mismatch_behavior to "drop_block", or strip the thinking blocks as above and retry once.

FAQ

Does switching Claude accounts or API keys cause this error?

No. A signature does not stop verifying because the account changed. The only account-bound blocks are Sonnet 5.5 and Haiku 5.5 thinking blocks, and when the account differs the API drops them silently and the request succeeds instead of returning a 400.

Will retrying fix it?

Not as is: the same request body is rejected every time. Either remove the thinking and redacted_thinking blocks from the history and resend, or start a new conversation. For the prefix-check version you can also send the thinking-binding-controls-2026-08-01 beta header and set thinking.block_binding.prefix_mismatch_behavior to "drop_block".

Why does switching from DeepSeek or similar models to Claude trigger it?

Their Anthropic-compatible APIs also return thinking blocks, but the signature is the provider's own string or empty, which Claude cannot verify. When the same session moves to Claude those blocks are sent along, and Claude returns a 400. Start a new session when you switch providers, or strip the thinking blocks from the history first.

What if Claude Code keeps showing this error?

Recent Claude Code versions strip the thinking blocks and retry automatically, so run claude update first. If every turn still fails after updating, use /rewind to go back to a turn before the problem, or /clear to start a new conversation.