API 检查了您发回的 thinking 块,但签名验证失败:签名被截断、修改或以空值发回,或者该块从未由 Claude 签名——又或者,在 Claude Fable 5.1 和 Claude Opus 5.5 上,对话中更早的内容发生了变化。每次重新发送相同历史都会以同样方式失败。找出破坏签名的原因,然后从该对话中一次性移除 thinking 块并继续——您会失去模型先前的推理,但不会失去对话。
错误
// 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"."原因和解决方法一览
| 原因 | 解决方法 |
|---|---|
| 签名在返回前被截断、清空或编辑 | 按照返回时的原样准确存储并重放每个块。让 SDK 组装流式轮次,避免丢失 signature_delta。 |
| 该块从未由 Claude 签名 | Anthropic 兼容 URL 背后的非 Claude 模型,或自行写入签名的代理。将这些轮次作为纯文本和 tool_use 发回。 |
| 您在对话中途切换了基础 URL、账户或登录方式 | Claude Code 2.1.152+ 会在切换模型或登录方式后移除过期签名。在您自己的代码中,如果切换后的第一个请求失败,请一次性移除 thinking。 |
| “该块绑定到了不同的对话”(Fable 5.1、Opus 5.5) | 系统提示、工具或更早的消息发生了变化。保持历史只追加不修改,或者选择 drop_block(需要 beta 标头)。 |
| 代理或网关在传输过程中重写了历史 | 它的重写会被视为您的编辑。直接针对 API 重现请求,以判断是否由此导致。 |
查看哪项检查失败
错误措辞会告诉您原因。如果消息停留在“thinking 块中的 `signature` 无效”,说明签名本身未通过验证:Anthropic 列出的原因包括签名被截断、修改或以空值发回(https://platform.claude.com/docs/en/build-with-claude/thinking-troubleshooting,截至 2026 年 9 月),其 preserved-thinking 页面称这是被篡改或无法解密的签名,并且始终返回 400。被掩码为 ***.***.content.0 的路径,或网关追加的请求 ID,都不会改变这一点;关键在于后面是否还有关于对话的句子。在 Claude Fable 5.1 和 Claude Opus 5.5 上,相同措辞可能继续显示“该块绑定到了不同的对话”——这是另一项检查,在最后一步介绍。第三种消息“最新 assistant 消息中的块不能被修改”表示最新 assistant 轮次被编辑、过滤、重新排序或重建;编辑 thinking 文本会产生该错误,而不是签名错误。重试相同请求体无法清除其中任何一种错误。
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按返回原样发回 assistant 轮次
每个 thinking 块都带有签名——完整推理的加密副本——API 使用它来验证该块由 Claude 生成(https://platform.claude.com/docs/en/build-with-claude/thinking#thinking-encryption)。原样追加响应的内容列表:thinking、redacted_thinking 和 tool_use 块,包括文本为空的 thinking 块;在较新的模型上,这是默认显示方式。使用流式传输时,签名会在块关闭前通过单个 signature_delta 到达,因此手写的累加器如果漏掉它,就会存储空签名,带空签名发回的块会失败;Anthropic 建议让 SDK 组装消息。JSON 键的顺序和空白不重要——值才重要。
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.不要将其他后端的 thinking 放入 Claude 历史
根据 Anthropic 的文档,在其自身 API 上切换 Claude 模型不应触发此错误:文档要求您在切换时继续发送这些块,无法读取的块会被新模型无错误地丢弃,并说明签名可在 Claude API、Amazon Bedrock 和 Google Cloud 之间移植(https://platform.claude.com/docs/en/build-with-claude/thinking,截至 2026 年 9 月)。但它无法验证从未由 Claude 签名的块。公开报告涉及经过其他后端的历史:一个先在 GLM 后端运行、再返回 Anthropic 的 Claude Code 会话(github.com/anthropics/claude-code/issues/21726);一个代理将 Gemini 轮次伪装成带有自身签名的 Claude thinking 块(github.com/router-for-me/CLIProxyAPI/issues/1584);以及一个在会话中途切换到另一把密钥、再切回的 Claude Code 会话(github.com/lbjlaq/Antigravity-Manager/issues/388)。对于非 Claude 模型生成的轮次,Anthropic 的建议是仅将该模型的输出作为文本和 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")]恢复已经失败的对话
从已存储的历史中一次性移除 thinking 和 redacted_thinking 块——全部移除最简单;对于“绑定到了不同的对话”这一变体,Anthropic 明确的最低要求是移除指定块及其之后的每一个块——保留其他所有块的原有位置,保存该历史并继续。Anthropic 将此作为无法再重放的已保存会话的恢复方法(https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#faq);如果签名无法验证,唯一的其他方法是按返回时的原样重放该块,前提是您仍然保留它。Claude Code 在 API 拒绝签名时会自行移除较早的 thinking。移除这些块并继续后,不要再放回它们:在 Fable 5.1 上,被移除后又放回的块会使其缺失期间产生的 thinking 失效。模型会在没有先前推理的情况下回答,从这里开始产生的新 thinking 有效。在 Claude Code 中,2.1.152(2026 年 5 月 27 日,https://code.claude.com/docs/en/changelog)会在切换模型或登录身份后移除过期签名,其网关指南说明它会在没有较早 thinking 块的情况下重试签名拒绝——但该重试依赖上游错误措辞匹配,而用自身信封包装错误的网关可能使其失效(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 blocks在 Fable 5.1 上固定前缀——或选择 drop_block
“Bound to a different conversation”(“绑定到了不同的对话”)是 preserved-thinking 检查:在 Claude Fable 5.1 和 Claude Opus 5.5 上,重放的块只有在系统提示、工具和所有更早消息均未改变时才有效。对于 2026 年 8 月 31 日或之后创建的账户,Anthropic 默认强制执行该规则(https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#enforcement);通过网关时,该账户并不属于您,因此应假设该规则已启用。在会话期间保持系统提示和工具固定,只追加,不编辑。为了在查找导致问题的编辑时保持请求成功,请发送 thinking-binding-controls-2026-08-01 beta 标头,并将 prefix_mismatch_behavior 设置为 drop_block;没有该标头时,该字段本身会被拒绝,并显示“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": "..."}]
}'如果你通过 Kunavo 调用
Kunavo 会按发送时的原样通过 /v1/messages 转发 thinking 和 redacted_thinking 块,包括签名和数据——唯一的请求更改是模型 ID,以及在拒绝这些参数的模型上移除 temperature、top_p 和 top_k——并按上游发送的方式返回响应正文,无论是否为流式响应。截至 2026 年 9 月,每个 Claude 模型都通过一个上游通道提供服务,没有备用通道,因此 Kunavo 的路由不会在提供商之间移动对话,400 错误也绝不会在其他地方重试。我们尚未测试在 Anthropic 直连与 Kunavo 之间移动对话,因此预计切换后的第一个请求需要移除 thinking。自 2026 年 9 月 24 日起,Kunavo 会转发 thinking-binding-controls-2026-08-01 beta;当天的一项测试中,为 Claude Fable 5.1 提供服务的通道在有或没有该标头的情况下都接受 block_binding,我们尚未观察到它丢弃块。拒绝会以 HTTP 400、类型为 invalid_request_error 的形式返回,不包含 request_id 字段,并携带上游的消息文本——该文本可能掩盖 messages.N 路径,并以上游自己的请求 ID 结尾——因此请根据状态码和“Invalid `signature` in `thinking` block”这几个词进行匹配。Claude Code 的自动移除并重试功能依赖该措辞:Claude Code 2.1.280 指向一个以此信封响应的测试服务器时,移除了 thinking 块并重试。我们尚未通过 Kunavo 本身触发该错误,因此如果会话仍然在每一轮都失败,请开始新会话。失败的请求不收费。 原生端点原样转发的内容列于 Messages API 参考.
常见问题
“thinking 块中的 `signature` 无效”是什么意思?
API 无法验证您发回的 thinking 块。每个 thinking 块都带有签名——Claude 推理的加密副本——当签名被截断、修改或以空值发回,或者该块从未由 Claude 签名时,验证就会失败。这是 400 错误,而不是暂时性错误:相同请求每次都会失败。
thinking 块签名会过期吗?
Anthropic 的文档没有提到过期。在 anthropic-sdk-python 跟踪器(问题 #1598,2026 年 8 月)中,一位 GitHub 标记为贡献者的账户回复称签名不会过期,并表示当到达 API 的块与返回的块不一致时检查会失败——但这是一条问题评论,而不是文档。如果以前能够正常工作的已保存会话现在失败,请检查哪些因素可能改变了已存储的块或它们经过的路由:存储层、代理或后端切换。
我可以直接删除 thinking 块并继续吗?
可以。Anthropic 将其作为无法重放的已保存会话的恢复方法,Claude Code 在签名被拒绝时也会自行移除较早的 thinking。移除 thinking 和 redacted_thinking 块——全部移除最简单——保留其他块,然后重试一次。模型会失去先前的推理,但不会失去对话;对于不涉及工具使用的情况,Anthropic 文档也允许省略较早轮次的 thinking。
为什么在切换模型或提供商后会发生?
Anthropic 文档称,在其 API 上切换 Claude 模型时,新模型无法读取的块会被丢弃且不会报错,并且签名可跨 Claude API、Amazon Bedrock 和 Google Cloud 使用。Claude Code 仍然需要修复在模型或登录方式切换后因过期签名而卡住的会话(2.1.152);公开报告涉及经过 Claude 无法验证的内容——同一基础 URL 背后的非 Claude 模型、写入自身签名的代理,或丢失签名的客户端。切换后一次性移除 thinking 块。
Claude Code 会自动修复吗?
较新版本会尝试修复。自 2.1.152 起,它会在模型或登录方式切换后移除过期签名,并在不带较早 thinking 块的情况下重试签名拒绝。该重试依赖上游错误措辞匹配,而 Anthropic 的网关指南指出,用自身信封包装错误的网关可能使其失效。请先运行 claude update;如果某个会话仍然在每一轮都失败,请开始新会话。