La API comprobó la firma de un bloque de pensamiento que volviste a enviar y no se verificó: la firma se truncó, se alteró o se volvió a enviar vacía, o el bloque nunca fue firmado por Claude; o, en Claude Fable 5.1 y Claude Opus 5.5, algo anterior de la conversación cambió. Volver a enviar el mismo historial falla de la misma manera cada vez. Encuentra qué lo rompió y elimina los bloques de pensamiento de esa conversación una vez para continuar; pierdes el razonamiento anterior del modelo, no la conversación.
El error
// 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 y soluciones de un vistazo
| Causa | Solución |
|---|---|
| La firma se truncó, quedó vacía o se editó antes de volver a enviarse | Almacena y reproduce cada bloque exactamente como se devolvió. Deja que el SDK ensamble los turnos transmitidos para que no se pierda signature_delta. |
| Claude nunca firmó el bloque | Un modelo que no es Claude detrás de una URL compatible con Anthropic, o un proxy que escribe sus propias firmas. Devuelve esos turnos solo como texto y bloques tool_use. |
| Cambiaste la URL base, la cuenta o el inicio de sesión durante la conversación | Claude Code 2.1.152+ elimina las firmas obsoletas después de cambiar de modelo o de inicio de sesión. En tu propio código, elimina los bloques de pensamiento una vez si la primera solicitud después del cambio falla. |
| «El bloque está vinculado a una conversación diferente» (Fable 5.1, Opus 5.5) | El prompt del sistema, las herramientas o un mensaje anterior cambió. Mantén el historial en modo append-only o activa drop_block (requiere un encabezado beta). |
| Un proxy o gateway reescribe el historial durante el tránsito | Sus reescrituras cuentan como tus ediciones. Reproduce la solicitud directamente contra la API para confirmar o descartar esta causa. |
Lee qué comprobación falló
El texto lo indica. Un mensaje que termina en «Invalid `signature` in `thinking` block» significa que la firma en sí no se verificó: Anthropic enumera como causas que esté truncada, alterada o se haya vuelto a enviar vacía (https://platform.claude.com/docs/en/build-with-claude/thinking-troubleshooting, a fecha de septiembre de 2026), y su página sobre el pensamiento preservado lo describe como una firma manipulada o imposible de descifrar que siempre devuelve un 400. Una ruta enmascarada como ***.***.content.0 o un ID de solicitud añadido por un gateway no cambia eso; lo importante es si después aparece una frase sobre la conversación. En Claude Fable 5.1 y Claude Opus 5.5, las mismas palabras pueden continuar con «The block is bound to a different conversation»: es una comprobación diferente, cubierta en el último paso. Un tercer mensaje, «blocks in the latest assistant message cannot be modified», significa que el turno más reciente del asistente se editó, filtró, reordenó o reconstruyó; el texto de pensamiento editado produce ese error, no un error de firma. Reintentar el mismo cuerpo no elimina ninguno de ellos.
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 backDevuelve los turnos del asistente exactamente como se recibieron
Cada bloque de pensamiento lleva una firma —una copia cifrada de todo el razonamiento— y la API la utiliza para verificar que Claude generó el bloque (https://platform.claude.com/docs/en/build-with-claude/thinking#thinking-encryption). Añade intacta la lista de contenido de la respuesta: bloques thinking, redacted_thinking y tool_use, incluidos los bloques thinking cuyo texto está vacío, que es la visualización predeterminada en los modelos más recientes. Al transmitir, la firma llega en un único signature_delta justo antes de que se cierre el bloque, por lo que un acumulador creado manualmente que no lo detecte guarda una firma vacía, y un bloque reenviado con una firma vacía falla; el consejo de Anthropic es dejar que el SDK ensamble el mensaje. El orden de las claves JSON y los espacios en blanco no importan; los valores sí.
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.Mantén fuera del historial de Claude el pensamiento de otros backends
Según la documentación de Anthropic, cambiar entre modelos de Claude en su propia API no debería provocar esto: te pide seguir enviando los bloques al cambiar, descarta sin error los que el nuevo modelo no puede leer y documenta que las firmas son portables entre Claude API, Amazon Bedrock y Google Cloud (https://platform.claude.com/docs/en/build-with-claude/thinking, a fecha de septiembre de 2026). Lo que no puede verificar es un bloque que Claude nunca firmó. Los informes públicos incluyen historiales que pasaron por otro backend: una sesión de Claude Code que se ejecutó con un backend GLM y luego volvió a Anthropic (github.com/anthropics/claude-code/issues/21726), turnos de Gemini que un proxy presentó como bloques de pensamiento de Claude con firmas propias (github.com/router-for-me/CLIProxyAPI/issues/1584), y una sesión de Claude Code que cambió a otra clave a mitad de la sesión y luego volvió (github.com/lbjlaq/Antigravity-Manager/issues/388). Para los turnos producidos por un modelo que no sea Claude, el consejo de Anthropic es devolver la salida de ese modelo únicamente como contenido de texto y tool_use.
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")]Recupera una conversación que ya falla
Elimina una sola vez los bloques thinking y redacted_thinking del historial almacenado —lo más sencillo es eliminarlos todos—; para la variante «vinculado a una conversación diferente», el mínimo indicado por Anthropic es el bloque mencionado y todos los posteriores. Conserva los demás bloques en su lugar, guarda ese historial y continúa. Anthropic ofrece esto como recuperación para una sesión guardada que ya no se puede reproducir (https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#faq); cuando una firma no se verifica, la única otra salida es reproducir el bloque exactamente como se devolvió, si aún lo tienes. Claude Code elimina por sí mismo el pensamiento anterior cuando la API rechaza una firma. Una vez eliminados los bloques y continuado el proceso, no los vuelvas a añadir: en Fable 5.1, un bloque eliminado y vuelto a añadir invalida el pensamiento producido mientras estaba ausente. El modelo responde sin su razonamiento anterior, y el pensamiento nuevo es válido desde ese momento. En Claude Code, 2.1.152 (27 de mayo de 2026, https://code.claude.com/docs/en/changelog) elimina las firmas obsoletas después de cambiar de modelo o de inicio de sesión, y su guía de gateway indica que reintenta un rechazo de firma sin los bloques de pensamiento anteriores; pero ese reintento se basa en el texto del error del upstream, y un gateway que envuelve los errores en su propio contenedor puede romperlo (https://code.claude.com/docs/en/llm-gateway-protocol#automatic-retry-and-error-forwarding).
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 blocksEn Fable 5.1, mantén fijo el prefijo o activa drop_block
«Vinculado a una conversación diferente» es la comprobación del pensamiento preservado: en Claude Fable 5.1 y Claude Opus 5.5, un bloque reproducido solo es válido mientras el prompt del sistema, las herramientas y todos los mensajes anteriores permanezcan sin cambios. Anthropic lo aplica de forma predeterminada a las cuentas creadas el 31 de agosto de 2026 o después (https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#enforcement); detrás de un gateway esa cuenta no es tuya, así que da por hecho que está activado. Mantén fijos el sistema y las herramientas durante la sesión y añade contenido en lugar de editarlo. Para que las solicitudes sigan funcionando mientras encuentras la edición, envía el encabezado beta thinking-binding-controls-2026-08-01 con prefix_mismatch_behavior establecido en drop_block; sin ese encabezado, el propio campo se rechaza con «block_binding: Extra inputs are not permitted» (https://platform.claude.com/docs/en/api/errors).
# 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": "..."}]
}'Si llamas a través de Kunavo
Kunavo transmite los bloques thinking y redacted_thinking a través de /v1/messages tal como se enviaron, con la firma y los datos incluidos; los únicos cambios en la solicitud son el ID del modelo y, en los modelos que los rechazan, la eliminación de temperature, top_p y top_k; y devuelve el cuerpo de la respuesta, con transmisión o sin ella, tal como lo envió el upstream. A fecha de septiembre de 2026, cada modelo de Claude se ofrece a través de un único canal upstream sin fallback, por lo que el enrutamiento de Kunavo no mueve una conversación entre proveedores y un 400 nunca se reintenta en otro lugar. No hemos probado mover una conversación entre Anthropic directo y Kunavo, así que espera que la primera solicitud después de ese cambio necesite eliminar el pensamiento. Desde el 24 de septiembre de 2026, Kunavo reenvía el beta thinking-binding-controls-2026-08-01; en una prueba realizada ese día, el canal que servía Claude aceptó block_binding en Claude Fable 5.1 con o sin el encabezado, y no hemos visto que elimine ningún bloque. El rechazo llega como HTTP 400 de tipo invalid_request_error, sin un campo request_id, y contiene el texto del mensaje del upstream, que puede ocultar la ruta messages.N y terminar con el propio ID de solicitud del upstream; por eso hay que coincidir con el estado y las palabras «Invalid `signature` in `thinking` block». La eliminación y el reintento automáticos de Claude Code se basan en ese texto: Claude Code 2.1.280, apuntando a un servidor de prueba que respondía con este contenedor, eliminó los bloques de pensamiento y reintentó. No hemos provocado el error a través de Kunavo, así que, si una sesión sigue fallando en cada turno, inicia una nueva. Las solicitudes fallidas no se facturan. Lo que el endpoint nativo transmite sin modificaciones se enumera en la referencia de la Messages API.
Preguntas frecuentes
¿Qué significa «Invalid `signature` in `thinking` block»?
La API no pudo verificar un bloque de pensamiento que volviste a enviar. Cada bloque de pensamiento lleva una firma —una copia cifrada del razonamiento de Claude— y la comprobación falla cuando esa firma se truncó, se alteró o se volvió a enviar vacía, o cuando Claude nunca firmó el bloque. Es un 400, no un error transitorio: la misma solicitud falla cada vez.
¿Caducan las firmas de los bloques de razonamiento?
La documentación de Anthropic no menciona ninguna caducidad. En el rastreador de anthropic-sdk-python (issue n.º 1598, agosto de 2026), una respuesta de una cuenta que GitHub marca como colaboradora afirma que no caducan y que la comprobación falla cuando el bloque que llega a la API difiere del que se devolvió; es un comentario en una issue, no documentación. Si una sesión guardada que antes funcionaba ahora falla, comprueba qué podría haber cambiado los bloques almacenados o la ruta que siguieron: tu capa de almacenamiento, un proxy o un cambio de backend.
¿Puedo simplemente eliminar los bloques de razonamiento y continuar?
Sí. Anthropic lo indica como recuperación para una sesión guardada que no se puede reproducir, y Claude Code elimina por sí mismo el razonamiento anterior cuando se rechaza una firma. Elimina los bloques de thinking y redacted_thinking —lo más sencillo es eliminarlos todos—, conserva los demás bloques y vuelve a intentarlo una vez. El modelo pierde su razonamiento anterior, no la conversación; fuera del uso de herramientas, la documentación de Anthropic permite omitir también el razonamiento de turnos anteriores.
¿Por qué ocurre después de cambiar de modelo o proveedor?
La documentación de Anthropic indica que un cambio entre modelos Claude en su API elimina los bloques que el nuevo modelo no puede leer, sin producir un error, y que las firmas funcionan en la Claude API, Amazon Bedrock y Google Cloud. Claude Code aun así tuvo que corregir sesiones bloqueadas por firmas obsoletas después de un cambio de modelo o de inicio de sesión (2.1.152), y los informes públicos implican un historial que pasó por algo que Claude no puede verificar: un modelo que no es Claude detrás de la misma URL base, un proxy que escribe sus propias firmas o un cliente que las perdió. Elimina los bloques de razonamiento una vez después del cambio.
¿Claude Code soluciona esto automáticamente?
Las versiones recientes lo intentan. Desde la 2.1.152 elimina las firmas obsoletas después de cambiar de modelo o iniciar sesión, y vuelve a intentar un rechazo de firma sin los bloques de razonamiento anteriores. Ese reintento busca coincidencias en el texto del error del proveedor ascendente, y la guía de gateways de Anthropic indica que un gateway que envuelve los errores en su propio contenedor puede romperlo. Ejecuta primero claude update; si una sesión sigue fallando en cada turno, inicia una sesión nueva.
Guías relacionadas
- Claude API 400 «tool_use ids were found without tool_result blocks» — la regla de orden
- Claude Code Router — dirige Claude Code a cualquier modelo o prescinde completamente del router
- Errores de streaming de LLM: cortes SSE, streams bloqueados y uso no informado
- Claude Code “context_management: Extra inputs are not permitted”: el encabezado beta que no llegó
Encontrarás más detalles sobre el significado de los errores en referencia de errores; obtener una clave lleva un minuto mediante registro y la guía de autenticación.