API đã kiểm tra chữ ký trên khối thinking bạn gửi lại nhưng không xác minh được: chữ ký bị cắt ngắn, thay đổi hoặc gửi lại ở trạng thái trống, hoặc khối này chưa từng được Claude ký — hoặc, trên Claude Fable 5.1 và Claude Opus 5.5, có điều gì đó trước đó trong cuộc hội thoại đã thay đổi. Gửi lại cùng một lịch sử sẽ luôn thất bại theo cùng cách. Hãy tìm điều đã làm hỏng chữ ký, rồi xóa các khối thinking khỏi cuộc hội thoại đó một lần và tiếp tục — bạn mất phần suy luận trước đó của mô hình, không mất cuộc hội thoại.
Lỗi
// 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"."Tổng quan nguyên nhân và cách khắc phục
| Nguyên nhân | Cách khắc phục |
|---|---|
| Chữ ký bị cắt ngắn, làm trống hoặc chỉnh sửa trước khi được gửi lại | Lưu trữ và phát lại từng khối chính xác như khi được trả về. Hãy để SDK lắp ráp các lượt truyền theo luồng để không làm mất signature_delta. |
| Khối này chưa từng được Claude ký | Một mô hình không phải Claude đứng sau URL tương thích Anthropic hoặc một proxy tự ghi chữ ký. Hãy gửi lại các lượt đó chỉ dưới dạng văn bản và tool_use. |
| Bạn đã chuyển base URL, tài khoản hoặc thông tin đăng nhập giữa cuộc hội thoại | Claude Code 2.1.152+ loại bỏ các chữ ký cũ sau khi chuyển mô hình hoặc đăng nhập. Trong mã của bạn, hãy xóa thinking một lần nếu yêu cầu đầu tiên sau khi chuyển đổi thất bại. |
| “Khối này được liên kết với một cuộc hội thoại khác” (Fable 5.1, Opus 5.5) | System prompt, công cụ hoặc một tin nhắn trước đó đã thay đổi. Hãy giữ lịch sử chỉ được nối thêm hoặc chọn drop_block (cần tiêu đề beta). |
| Proxy hoặc gateway viết lại lịch sử trên đường truyền | Các lần viết lại của nó được tính như chỉnh sửa của bạn. Hãy tái hiện trực tiếp với API để xác định có phải nguyên nhân này hay không. |
Đọc xem bước kiểm tra nào thất bại
Cách diễn đạt sẽ cho bạn biết. Một thông báo dừng ở “Chữ ký `signature` không hợp lệ trong khối `thinking`” có nghĩa là bản thân chữ ký không xác minh được: Anthropic liệt kê các nguyên nhân là bị cắt ngắn, thay đổi hoặc gửi lại ở trạng thái trống (https://platform.claude.com/docs/en/build-with-claude/thinking-troubleshooting, tính đến tháng 9 năm 2026), và trang về thinking được bảo toàn gọi đó là chữ ký bị can thiệp hoặc không thể giải mã, luôn trả về lỗi 400. Một đường dẫn bị che dưới dạng ***.***.content.0 hoặc request id được gateway thêm vào không làm thay đổi điều đó; điều quan trọng là sau đó có câu nào nói về cuộc hội thoại hay không. Trên Claude Fable 5.1 và Claude Opus 5.5, cùng những từ đó có thể tiếp tục bằng “Khối này được liên kết với một cuộc hội thoại khác” — một bước kiểm tra khác, được đề cập ở bước cuối. Thông báo thứ ba, “các khối trong tin nhắn assistant mới nhất không thể bị sửa đổi”, có nghĩa là lượt assistant mới nhất đã bị chỉnh sửa, lọc, sắp xếp lại hoặc dựng lại; văn bản thinking bị chỉnh sửa sẽ tạo ra lỗi đó, không phải lỗi chữ ký. Thử lại cùng một nội dung không xóa được bất kỳ lỗi nào trong số này.
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 backGửi lại các lượt assistant chính xác như khi được trả về
Mỗi khối thinking mang một chữ ký — một bản mã hóa của toàn bộ phần suy luận — và API dùng chữ ký đó để xác minh khối được Claude tạo ra (https://platform.claude.com/docs/en/build-with-claude/thinking#thinking-encryption). Hãy nối nguyên trạng danh sách content của phản hồi: các khối thinking, redacted_thinking và tool_use, bao gồm cả những khối thinking có văn bản trống, vốn là chế độ hiển thị mặc định trên các mô hình mới hơn. Khi truyền theo luồng, chữ ký xuất hiện trong một signature_delta duy nhất ngay trước khi khối đóng, vì vậy bộ tích lũy tự viết có thể bỏ sót nó, lưu chữ ký trống và khiến khối được gửi lại với chữ ký trống bị lỗi; khuyến nghị của Anthropic là để SDK lắp ráp tin nhắn. Thứ tự khóa JSON và khoảng trắng không quan trọng — các giá trị thì có.
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.Không đưa phần suy luận của các backend khác vào lịch sử Claude
Theo tài liệu của Anthropic, việc chuyển đổi giữa các mô hình Claude trên API của họ vốn không được gây ra điều này: họ yêu cầu bạn tiếp tục gửi các block khi chuyển đổi, tự loại bỏ những block mà mô hình mới không thể đọc mà không báo lỗi, và ghi rõ rằng chữ ký có thể dùng được giữa Claude API, Amazon Bedrock và Google Cloud (https://platform.claude.com/docs/en/build-with-claude/thinking, tính đến tháng 9 năm 2026). Điều họ không thể xác minh là một block mà Claude chưa từng ký. Các báo cáo công khai liên quan đến lịch sử đã đi qua một backend khác: một phiên Claude Code chạy trên backend GLM rồi quay lại Anthropic (github.com/anthropics/claude-code/issues/21726), các lượt Gemini mà một proxy giả dạng thành các block suy luận của Claude bằng chữ ký do chính nó tạo ra (github.com/router-for-me/CLIProxyAPI/issues/1584), và một phiên Claude Code chuyển sang khóa khác giữa chừng rồi quay lại (github.com/lbjlaq/Antigravity-Manager/issues/388). Với các lượt do mô hình không phải Claude tạo ra, lời khuyên của Anthropic là gửi lại đầu ra của mô hình đó chỉ dưới dạng nội dung text và 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")]Khôi phục một cuộc trò chuyện đã bị lỗi
Xóa các block thinking và redacted_thinking khỏi lịch sử đã lưu một lần — xóa tất cả là cách đơn giản nhất; với biến thể “bound to a different conversation”, mức tối thiểu mà Anthropic nêu là block được chỉ định và mọi block sau nó — giữ nguyên mọi block khác ở vị trí cũ, lưu lịch sử đó rồi tiếp tục. Anthropic đưa ra đây là cách khôi phục một phiên đã lưu không thể phát lại (https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#faq); khi chữ ký không được xác minh, cách duy nhất khác là phát lại chính xác block như lúc nó được trả về, nếu bạn vẫn còn block đó. Claude Code tự loại bỏ phần suy luận trước đó khi API từ chối chữ ký. Một khi đã xóa các block và tiếp tục, đừng thêm chúng trở lại: trên Fable 5.1, một block bị xóa rồi thêm lại sẽ làm mất hiệu lực phần suy luận được tạo ra trong thời gian block vắng mặt. Mô hình trả lời mà không có phần suy luận trước đó, và phần suy luận mới hợp lệ từ thời điểm đó. Trong Claude Code, phiên bản 2.1.152 (27 tháng 5 năm 2026, https://code.claude.com/docs/en/changelog) loại bỏ các chữ ký cũ sau khi chuyển đổi mô hình hoặc tài khoản đăng nhập, còn hướng dẫn gateway cho biết nó thử lại một lần từ chối chữ ký mà không có các block suy luận trước đó — nhưng lần thử lại này khớp theo cách diễn đạt lỗi của upstream, và một gateway bọc lỗi trong envelope riêng có thể làm hỏng cơ chế đó (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 blocksTrên Fable 5.1, giữ cố định phần tiền tố — hoặc chọn drop_block
“Bound to a different conversation” là cơ chế kiểm tra preserved-thinking: trên Claude Fable 5.1 và Claude Opus 5.5, một block được phát lại chỉ hợp lệ khi system prompt, các công cụ và mọi message trước đó không thay đổi. Anthropic bật cơ chế này theo mặc định cho các tài khoản được tạo từ ngày 31 tháng 8 năm 2026 trở đi (https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#enforcement); phía sau một gateway, tài khoản đó không thuộc về bạn, vì vậy hãy giả định cơ chế này đang bật. Giữ nguyên system và tools trong suốt phiên, đồng thời chỉ thêm mới thay vì chỉnh sửa. Để các request tiếp tục thành công trong khi bạn xác định chỗ đã bị chỉnh sửa, hãy gửi beta header thinking-binding-controls-2026-08-01 với prefix_mismatch_behavior được đặt thành drop_block; nếu không có header đó, chính trường này sẽ bị từ chối với “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": "..."}]
}'Nếu bạn gọi qua Kunavo
Kunavo chuyển tiếp các block thinking và redacted_thinking qua /v1/messages đúng như được gửi, bao gồm cả signature và data — các thay đổi duy nhất đối với request là model id và, trên các model từ chối chúng, việc loại bỏ temperature, top_p và top_k — đồng thời trả về response body, dù có stream hay không, đúng như upstream đã gửi. Tính đến tháng 9 năm 2026, mỗi mô hình Claude được cung cấp qua một kênh upstream duy nhất, không có fallback, vì vậy cơ chế định tuyến của Kunavo không chuyển một cuộc trò chuyện giữa các nhà cung cấp, và lỗi 400 không bao giờ được thử lại ở nơi khác. Chúng tôi chưa thử nghiệm việc chuyển một cuộc trò chuyện giữa Anthropic trực tiếp và Kunavo, vì vậy hãy dự kiến request đầu tiên sau khi chuyển đổi sẽ cần loại bỏ phần suy luận. Kể từ ngày 24 tháng 9 năm 2026, Kunavo chuyển tiếp beta thinking-binding-controls-2026-08-01; trong một thử nghiệm vào ngày đó, kênh cung cấp Claude đã chấp nhận block_binding trên Claude Fable 5.1 dù có hoặc không có header, và chúng tôi chưa thấy kênh này loại bỏ block nào. Phản hồi từ chối đến dưới dạng HTTP 400, kiểu invalid_request_error, không có trường request_id, chứa nội dung message của upstream — nội dung này có thể che khuất đường dẫn messages.N và kết thúc bằng request id riêng của upstream — vì vậy hãy khớp theo status và các từ “Invalid `signature` in `thinking` block”. Cơ chế tự động loại bỏ rồi thử lại của Claude Code dựa trên cách diễn đạt đó: Claude Code 2.1.280, khi trỏ tới một test server trả lời bằng envelope này, đã loại bỏ các block suy luận và thử lại. Chúng tôi chưa kích hoạt lỗi này thông qua chính Kunavo, vì vậy nếu một phiên vẫn thất bại ở mọi lượt, hãy bắt đầu phiên mới. Các request thất bại không bị tính phí. Những gì endpoint gốc chuyển tiếp nguyên trạng được liệt kê trong tài liệu tham khảo Messages API.
Câu hỏi thường gặp
“Invalid `signature` in `thinking` block” có nghĩa là gì?
API không thể xác minh một block suy luận mà bạn gửi lại. Mỗi block suy luận đều có một chữ ký — một bản sao được mã hóa của phần suy luận của Claude — và việc kiểm tra thất bại khi chữ ký đó bị cắt ngắn, bị thay đổi hoặc được gửi lại ở dạng rỗng, hoặc khi block chưa từng được Claude ký. Đây là lỗi 400, không phải lỗi tạm thời: cùng một request sẽ thất bại mọi lần.
Chữ ký của block suy luận có hết hạn không?
Tài liệu của Anthropic không đề cập đến thời hạn. Trên tracker anthropic-sdk-python (issue #1598, tháng 8 năm 2026), một phản hồi từ tài khoản được GitHub đánh dấu là contributor cho biết chúng không hết hạn, và việc kiểm tra thất bại khi block đến API khác với block đã được trả về — đây là bình luận trong issue, không phải tài liệu. Nếu một phiên đã lưu từng hoạt động nay bắt đầu lỗi, hãy xem điều gì có thể đã thay đổi các block được lưu hoặc tuyến đường chúng đi qua: lớp lưu trữ của bạn, một proxy hoặc việc chuyển đổi backend.
Tôi có thể chỉ cần xóa các block suy luận rồi tiếp tục không?
Có. Anthropic đưa ra đây là cách khôi phục một phiên đã lưu không thể phát lại, và Claude Code tự loại bỏ phần suy luận trước đó khi chữ ký bị từ chối. Hãy xóa các block thinking và redacted_thinking — xóa tất cả là cách đơn giản nhất — giữ lại các block khác rồi thử lại một lần. Mô hình mất phần suy luận trước đó, không mất cuộc trò chuyện; ngoài việc sử dụng công cụ, tài liệu của Anthropic cũng cho phép bỏ phần suy luận của các lượt trước.
Tại sao lỗi này xảy ra sau khi chuyển mô hình hoặc nhà cung cấp?
Tài liệu của Anthropic cho biết việc chuyển đổi giữa các mô hình Claude trên API của họ sẽ loại bỏ các block mà mô hình mới không thể đọc mà không báo lỗi, đồng thời chữ ký hoạt động xuyên suốt Claude API, Amazon Bedrock và Google Cloud. Claude Code vẫn phải sửa các phiên bị kẹt bởi chữ ký cũ sau khi chuyển mô hình hoặc đăng nhập (2.1.152), và các báo cáo công khai liên quan đến lịch sử đã đi qua thứ mà Claude không thể xác minh — một mô hình không phải Claude phía sau cùng base URL, một proxy tự tạo chữ ký hoặc một client làm mất chúng. Sau khi chuyển đổi, hãy xóa các block suy luận một lần.
Claude Code có tự động khắc phục việc này không?
Các phiên bản gần đây có cố gắng khắc phục. Kể từ 2.1.152, nó loại bỏ các chữ ký cũ sau khi chuyển mô hình hoặc đăng nhập, đồng thời thử lại khi chữ ký bị từ chối mà không có các block suy luận trước đó. Lần thử lại này khớp theo cách diễn đạt lỗi của upstream, và hướng dẫn gateway của Anthropic cho biết một gateway bọc lỗi trong envelope riêng có thể làm hỏng cơ chế đó. Trước tiên hãy chạy claude update; nếu một phiên vẫn thất bại ở mọi lượt, hãy bắt đầu phiên mới.
Hướng dẫn liên quan
- Claude API 400 “tool_use ids were found without tool_result blocks” — quy tắc thứ tự
- Claude Code Router — định tuyến Claude Code đến bất kỳ mô hình nào hoặc bỏ qua router hoàn toàn
- Lỗi streaming LLM — SSE bị ngắt, stream bị treo và thiếu usage
- Claude Code “context_management: Extra inputs are not permitted” — header beta đã không đến nơi
Thông tin chi tiết hơn về ý nghĩa lỗi có trong tài liệu tham chiếu lỗi; bạn chỉ mất một phút để lấy khóa qua đăng ký và hướng dẫn xác thực.