Voltar aos guias
Solução de problemas·23 de setembro de 2026·6 min de leitura

API do Claude 400 “Invalid `signature` in `thinking` block” — o que quebrou a assinatura e como recuperar

A API verificou a assinatura de um bloco de raciocínio que você reenviou e ela não foi validada: a assinatura foi truncada, alterada ou reenviada vazia, ou o bloco nunca foi assinado pelo Claude — ou, no Claude Fable 5.1 e no Claude Opus 5.5, algo anterior na conversa mudou. Reenviar o mesmo histórico falha da mesma maneira todas as vezes. Encontre o que quebrou e remova os blocos de raciocínio dessa conversa uma vez, depois continue — você perde o raciocínio anterior do modelo, não a conversa.

Última revisão em .

A API verificou a assinatura de um bloco de raciocínio que você reenviou e ela não foi validada: a assinatura foi truncada, alterada ou reenviada vazia, ou o bloco nunca foi assinado pelo Claude — ou, no Claude Fable 5.1 e no Claude Opus 5.5, algo anterior na conversa mudou. Reenviar o mesmo histórico falha da mesma maneira todas as vezes. Encontre o que quebrou e remova os blocos de raciocínio dessa conversa uma vez, depois continue — você perde o raciocínio anterior do modelo, não a conversa.

O erro

response (HTTP 400)
// Through Kunavo: the upstream message as it reaches you, typed as Anthropic
// types a 400; no request_id field, the upstream's own id is appended instead:
{"type":"error","error":{"type":"invalid_request_error","message":"messages.1.content.0: Invalid `signature` in `thinking` block (request id: …)"}}
// (the message path, any masking of it and the appended request id vary by upstream)

// From Anthropic's API directly:
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "messages.1.content.0: Invalid `signature` in `thinking` block"
  },
  "request_id": "req_011C..."
}

// messages.{i}.content.{j}: i = position in messages[], j = block index. Both vary.
// An upstream can mask that path (***.***) and append its own request id, as above.
// Claude Code prints the body after "API Error: 400".
// On Claude Fable 5.1 and Claude Opus 5.5 the message can continue:
//   "... The block is bound to a different conversation. Remove the block, or set
//    `thinking.block_binding.prefix_mismatch_behavior` to "drop_block"."

Causas e soluções em resumo

CausaSolução
A assinatura foi truncada, esvaziada ou editada antes de ser reenviadaArmazene e reproduza cada bloco exatamente como foi retornado. Deixe o SDK montar os turnos transmitidos para que o signature_delta não seja perdido.
O bloco nunca foi assinado pelo ClaudeUm modelo que não é Claude por trás de uma URL compatível com Anthropic ou um proxy que grava suas próprias assinaturas. Reenvie esses turnos apenas como texto e tool_use.
Você trocou a base URL, a conta ou o login no meio da conversaO Claude Code 2.1.152+ remove assinaturas obsoletas após uma troca de modelo ou login. No seu próprio código, remova o bloco de raciocínio uma vez se a primeira solicitação após a troca falhar.
“O bloco está vinculado a uma conversa diferente” (Fable 5.1, Opus 5.5)O prompt do sistema, as ferramentas ou uma mensagem anterior mudou. Mantenha o histórico somente com acréscimos ou opte por drop_block (requer um cabeçalho beta).
Um proxy ou gateway reescreve o histórico durante o percursoEssas reescritas contam como suas edições. Reproduza diretamente na API para confirmar ou descartar essa hipótese.

Leia qual verificação falhou

A redação informa isso. Uma mensagem que termina em “Invalid `signature` in `thinking` block” significa que a própria assinatura não foi validada: a Anthropic lista como causas assinaturas truncadas, alteradas ou devolvidas vazias (https://platform.claude.com/docs/en/build-with-claude/thinking-troubleshooting, em setembro de 2026), e sua página sobre thinking preservado chama isso de uma assinatura adulterada ou impossível de descriptografar que sempre retorna 400. Um caminho mascarado como ***.***.content.0 ou um ID de solicitação anexado por um gateway não muda isso; o que importa é se vem depois uma frase sobre a conversa. No Claude Fable 5.1 e no Claude Opus 5.5, as mesmas palavras podem continuar com “The block is bound to a different conversation” — uma verificação diferente, abordada na última etapa. Uma terceira mensagem, “blocks in the latest assistant message cannot be modified”, significa que o turno mais recente do assistente foi editado, filtrado, reordenado ou reconstruído; texto de thinking editado produz esse erro, não um erro de assinatura. Repetir o mesmo corpo não elimina nenhum deles.

three thinking-block 400s
Invalid `signature` in `thinking` block
  -> the signature did not verify: truncated, altered, empty, or not Claude's

Invalid `signature` in `thinking` block. The block is bound to a different conversation. ...
  -> Fable 5.1 / Opus 5.5: system, tools or an earlier message changed after the block was made

`thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified
  -> the newest assistant turn was edited, filtered, reordered or rebuilt before it was sent back

Envie os turnos do assistente exatamente como foram retornados

Cada bloco de thinking carrega uma assinatura — uma cópia criptografada de todo o raciocínio — e a API a utiliza para verificar se o bloco foi gerado pelo Claude (https://platform.claude.com/docs/en/build-with-claude/thinking#thinking-encryption). Anexe a lista de conteúdo da resposta sem alterações: blocos thinking, redacted_thinking e tool_use, incluindo blocos de thinking cujo texto esteja vazio, que é a exibição padrão nos modelos mais recentes. Durante o streaming, a assinatura chega em um único signature_delta imediatamente antes do fechamento do bloco; portanto, um acumulador feito manualmente que não o capture armazena uma assinatura vazia, e um bloco reenviado com assinatura vazia falha; a recomendação da Anthropic é deixar o SDK montar a mensagem. A ordem das chaves JSON e os espaços em branco não importam — os valores, sim.

replay_verbatim.py
import anthropic

client = anthropic.Anthropic(base_url="https://api.kunavo.com", api_key="sk-kn-...")

tools = [{
    "name": "get_weather",
    "description": "Current weather for a city.",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]
messages = [{"role": "user", "content": "What's the weather in Paris?"}]

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=16000,
    thinking={"type": "adaptive"},
    tools=tools,
    messages=messages,
) as stream:
    final = stream.get_final_message()   # signature_delta already applied

# Append the content list untouched: thinking, redacted_thinking, tool_use.
messages.append({"role": "assistant", "content": final.content})

# Not this: a store that keeps the text but not the signature replays
# {"type": "thinking", "thinking": "...", "signature": ""}  -> this 400.

Mantenha o thinking de outros backends fora do histórico do Claude

Segundo a documentação da Anthropic, alternar entre modelos Claude na própria API não deve causar isso: ela pede que você continue enviando os blocos ao alternar, descarta os que o novo modelo não consegue ler sem gerar erro e documenta as assinaturas como portáteis entre a Claude API, o Amazon Bedrock e o Google Cloud (https://platform.claude.com/docs/en/build-with-claude/thinking, em setembro de 2026). O que ela não consegue verificar é um bloco que o Claude nunca assinou. Os relatos públicos envolvem históricos que passaram por outro backend: uma sessão do Claude Code que executou em um backend GLM e depois voltou à Anthropic (github.com/anthropics/claude-code/issues/21726), turnos do Gemini que um proxy apresentou como blocos de thinking do Claude com assinaturas próprias (github.com/router-for-me/CLIProxyAPI/issues/1584), e uma sessão do Claude Code que mudou para outra chave no meio da sessão e voltou (github.com/lbjlaq/Antigravity-Manager/issues/388). Para turnos produzidos por um modelo que não seja Claude, a recomendação da Anthropic é reenviar a saída desse modelo apenas como conteúdo de texto e tool_use.

foreign_turn.py
def as_foreign_turn(content: list[dict]) -> list[dict]:
    """A turn a non-Claude model produced: keep what it said and did,
    never its thinking blocks, which Claude cannot verify."""
    return [b for b in content if b["type"] in ("text", "tool_use")]

Recupere uma conversa que já apresenta falhas

Remova uma vez os blocos thinking e redacted_thinking do histórico armazenado — remover todos é o mais simples; para a variante “bound to a different conversation”, o mínimo declarado pela Anthropic é o bloco indicado e todos os blocos posteriores — mantenha todos os outros blocos no lugar, salve esse histórico e continue. A Anthropic apresenta isso como recuperação para uma sessão salva que não pode mais ser reproduzida (https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#faq); quando uma assinatura não é validada, a única outra saída é reproduzir o bloco exatamente como foi retornado, se você ainda o tiver. O Claude Code remove sozinho o thinking anterior quando a API rejeita uma assinatura. Depois de remover os blocos e prosseguir, não os coloque de volta: no Fable 5.1, um bloco removido e recolocado invalida o thinking produzido enquanto ele esteve ausente. O modelo responde sem o raciocínio anterior, e o novo thinking é válido a partir daí. No Claude Code, a versão 2.1.152 (27 de maio de 2026, https://code.claude.com/docs/en/changelog) remove assinaturas obsoletas após uma troca de modelo ou login, e seu guia de gateway informa que ele repete uma rejeição de assinatura sem os blocos de thinking anteriores — mas essa repetição procura o texto de erro do upstream, e um gateway que envolve os erros em seu próprio envelope pode quebrá-la (https://code.claude.com/docs/en/llm-gateway-protocol#automatic-retry-and-error-forwarding).

strip_thinking.py
THINKING = {"thinking", "redacted_thinking"}

def block_type(b) -> str:
    return b["type"] if isinstance(b, dict) else b.type   # dicts or SDK objects

def strip_thinking(messages: list[dict]) -> list[dict]:
    """One-time recovery: drop every thinking block, keep everything else."""
    out = []
    for m in messages:
        content = m["content"]
        if m["role"] == "assistant" and isinstance(content, list):
            kept = [b for b in content if block_type(b) not in THINKING]
            content = kept or [{"type": "text", "text": "(no visible reply)"}]  # keep the turn non-empty
        out.append({**m, "content": content})
    return out

messages = strip_thinking(messages)   # save this version; never re-add the blocks

No Fable 5.1, mantenha o prefixo fixo — ou opte por drop_block

“Bound to a different conversation” é a verificação de thinking preservado: no Claude Fable 5.1 e no Claude Opus 5.5, um bloco reproduzido só é válido enquanto o prompt do sistema, as ferramentas e todas as mensagens anteriores permanecerem inalterados. A Anthropic aplica isso por padrão a contas criadas em ou após 31 de agosto de 2026 (https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#enforcement); atrás de um gateway, essa conta não é sua, portanto, presuma que a regra está ativa. Mantenha o sistema e as ferramentas fixos durante a sessão e anexe em vez de editar. Para manter as solicitações funcionando enquanto você identifica a edição, envie o cabeçalho beta thinking-binding-controls-2026-08-01 com prefix_mismatch_behavior definido como drop_block; sem esse cabeçalho, o próprio campo é rejeitado com “block_binding: Extra inputs are not permitted” (https://platform.claude.com/docs/en/api/errors).

drop_block.sh
# Anthropic's API directly. The field needs the beta header; Kunavo forwards it (see below).
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: thinking-binding-controls-2026-08-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-fable-5-1",
    "max_tokens": 16000,
    "thinking": {
      "type": "adaptive",
      "block_binding": {"prefix_mismatch_behavior": "drop_block"}
    },
    "messages": [{"role": "user", "content": "..."}]
  }'

Se você estiver chamando pela Kunavo

O Kunavo encaminha os blocos thinking e redacted_thinking por /v1/messages exatamente como foram enviados, incluindo assinatura e dados — as únicas alterações na solicitação são o ID do modelo e, nos modelos que os rejeitam, a remoção de temperature, top_p e top_k — e retorna o corpo da resposta, com ou sem streaming, exatamente como o upstream o enviou. Em setembro de 2026, cada modelo Claude é servido por um único canal upstream, sem fallback; portanto, o roteamento do Kunavo não move uma conversa entre provedores, e um 400 nunca é repetido em outro local. Não testamos mover uma conversa entre a Anthropic diretamente e o Kunavo, então espere que a primeira solicitação após essa troca precise ter o thinking removido. Desde 24 de setembro de 2026, o Kunavo encaminha o beta thinking-binding-controls-2026-08-01; em um teste realizado naquele dia, o canal que servia o Claude aceitou block_binding no Claude Fable 5.1 com ou sem o cabeçalho, e não observamos a remoção de um bloco. A rejeição chega como HTTP 400 do tipo invalid_request_error, sem um campo request_id, contendo o texto da mensagem do upstream — que pode mascarar o caminho messages.N e terminar com o próprio request id do upstream — portanto, faça a correspondência pelo status e pelas palavras “Invalid `signature` in `thinking` block”. A remoção e repetição automáticas do Claude Code usam essa redação como chave: o Claude Code 2.1.280, apontado para um servidor de teste que respondia nesse envelope, removeu os blocos de thinking e repetiu a solicitação. Não provocamos o erro pelo próprio Kunavo; portanto, se uma sessão continuar falhando em todos os turnos, inicie uma nova. Solicitações com falha não são cobradas. O que o endpoint nativo encaminha sem alterações está listado na referência da Messages API.

Perguntas frequentes

O que significa “Invalid `signature` in `thinking` block”?

A API não conseguiu verificar um bloco de thinking que você reenviou. Cada bloco de thinking carrega uma assinatura — uma cópia criptografada do raciocínio do Claude — e a verificação falha quando essa assinatura foi truncada, alterada ou reenviada vazia, ou quando o bloco nunca foi assinado pelo Claude. É um 400, não um erro transitório: a mesma solicitação falha todas as vezes.

As assinaturas dos blocos de thinking expiram?

A documentação da Anthropic não menciona expiração. No rastreador do anthropic-sdk-python (issue #1598, agosto de 2026), uma resposta de uma conta que o GitHub identifica como colaboradora afirma que não expiram e que a verificação falha quando o bloco que chega à API difere do que foi retornado — é um comentário em issue, não documentação. Se uma sessão salva que funcionava antes agora falha, procure o que pode ter alterado os blocos armazenados ou o caminho que percorreram: sua camada de armazenamento, um proxy ou uma troca de backend.

Posso simplesmente excluir os blocos de thinking e continuar?

Sim. A Anthropic apresenta isso como recuperação para uma sessão salva que não pode ser reproduzida, e o Claude Code remove sozinho o thinking anterior quando uma assinatura é rejeitada. Remova os blocos thinking e redacted_thinking — remover todos é o mais simples — mantenha os outros blocos e repita uma vez. O modelo perde o raciocínio anterior, não a conversa; fora do uso de ferramentas, a documentação da Anthropic permite deixar de fora o thinking de turnos anteriores.

Por que isso acontece depois de trocar de modelo ou provedor?

A documentação da Anthropic afirma que uma troca entre modelos Claude em sua API descarta, sem erro, os blocos que o novo modelo não consegue ler, e que as assinaturas funcionam entre a Claude API, o Amazon Bedrock e o Google Cloud. Ainda assim, o Claude Code precisou corrigir sessões presas em assinaturas obsoletas após uma troca de modelo ou login (2.1.152), e os relatos públicos envolvem históricos que passaram por algo que o Claude não consegue verificar — um modelo que não é Claude atrás da mesma base URL, um proxy que escreve suas próprias assinaturas ou um cliente que as perdeu. Remova os blocos de thinking uma vez após a troca.

O Claude Code corrige isso automaticamente?

As versões recentes tentam fazer isso. Desde a 2.1.152, ele remove assinaturas obsoletas após uma troca de modelo ou login e repete uma rejeição de assinatura sem os blocos de thinking anteriores. Essa repetição procura o texto de erro do upstream, e o guia de gateway da Anthropic informa que um gateway que envolve os erros em seu próprio envelope pode quebrá-la. Execute claude update primeiro; se uma sessão ainda falhar em todos os turnos, inicie uma nova sessão.

Guias relacionados

Mais detalhes sobre o significado dos erros estão em referência de erros; obter uma chave leva um minuto por meio de cadastro e da guia de autenticação.