There is a 400 error in Claude Fable 5.1 that you will probably not see in development, will not see in staging, and will see in production — from users whose API accounts are newer than yours.
messages.5.content.0: 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".
It fires when your code does something that has been completely normal for two years: modifying the conversation history you send back to the model. Trimming an old turn. Swapping in a summary. Rebuilding the tools array between requests. Editing a previous assistant message before replaying it.
On claude-fable-5-1, released 1 September 2026, conversation history is effectively append-only. This piece is about what that means in code, which patterns just became illegal, what replaced them, and why the person who maintains an agent framework is the last to find out.
What a thinking block is actually bound to
Fable 5.1 runs adaptive thinking always on — it cannot be disabled, and thinking: {type: "disabled"} returns a 400 at any effort level. Every response therefore carries thinking blocks, and you pass them back on subsequent turns.
Those blocks are not inert payload. Each one carries a signature, and the documentation is precise about what it covers:
Each thinking block from Claude Fable 5.1 is valid only against the system prompt, tools, and conversation history that preceded it.
Three things, then, are frozen for the life of a thinking block:
- The system prompt as it was when the block was produced.
- The tools array as it was when the block was produced.
- Every message that came before it, byte for byte.
Change any one and send the block back, and the request is rejected. Not degraded — rejected, with a permanent error for that request body. As the docs put it: an automatic retry loop won't clear it.
There is a second binding on top of the first: blocks record which model produced them. Fable 5.1 reads its own blocks and those from Mythos 5.1, Opus 5, Fable 5, Mythos 5, and earlier models — so a conversation moving up to Fable 5.1 keeps its reasoning. The relationship is one-way. Apart from Mythos 5.1, none of those models can read Fable 5.1's blocks, so a conversation moving down to Opus 5 drops them.
Why you will find out last
This is the part worth reading twice, because it inverts the usual order of discovery.
The API enforces the check for new accounts created on or after August 31, 2026. For accounts created earlier, the API records the mismatch but doesn't act on it unless the request sets thinking.block_binding.prefix_mismatch_behavior, which opts into enforcement.
Your account is almost certainly older than 31 August 2026. Your CI account is older. Your team's accounts are older. On all of them, the API quietly notes the mismatch and serves the request anyway.
Your users' accounts are not older. Anyone who signed up this week is enforced by default.
Anthropic states the trap plainly: if you ship a tool or framework that people run with their own API key, test with the field set before launch, because your key is probably on an older account and your users on new ones hit the check before you do. And the reprieve is temporary — enforcement is planned for every account on future models.
So the practical reading is: this is a deadline, not an outage. You have one model generation to make your history handling append-only, and a free way to test against the future today.
To find out where your own account stands, send a request that edits history without the beta header. A 400 that names the header means you're enforced.
The patterns that are now illegal
If Claude Code, claude.ai, Claude Managed Agents, or the Claude Agent SDK owns your conversation history, they already keep the prefix intact and none of this applies. If your code builds the messages array itself, all of it applies. Here is the list, roughly in order of how common it is in real codebases.
1. Client-side truncation and summarization
The classic loop: when the conversation exceeds N tokens, drop or summarize the oldest turns and send the shortened array. Every thinking block after the edit point is now bound to a prefix that no longer exists.
2. Snipping a turn out of the middle
The worst case, and the one with no client-side workaround at all. The docs are blunt: don't do it — that invalidates every later thinking block and no client-side shape avoids it.
Easy to do by accident. A system prompt that interpolates the current date, a tools array assembled from a dict in non-deterministic order, a feature flag that adds a tool mid-session — each one changes the bound prefix. This is also, not coincidentally, the same class of bug that destroys your prompt cache hit rate; the two failures have exactly one root cause.
4. Keep-tail compaction
Summarize the old turns, keep the last few verbatim behind the summary. Those recent turns carry thinking produced against the full history, and they now sit behind a summary that replaced it. They fail.
5. Background compaction
Build the summary off the critical path, swap it in when ready. Every turn produced between the snapshot and the swap carries thinking that predates the new prefix.
6. Editing assistant turns for control
Rewriting a previous assistant message to steer the model, injecting synthetic assistant turns as few-shot examples mid-conversation, replaying a "corrected" version of what the model said. This family of techniques is what the change is aimed at — Anthropic frames it as an anti-distillation measure, describing it as no longer being possible for new API accounts to manually edit Claude's prior context in a multi-turn conversation while preserving the transcript of Claude's prior thinking.
Note that assistant prefill was already removed across the 4.6+ family, returning a 400. If you were reaching for prefill as the workaround here, that door closed first.
The three legal shapes for client-side compaction
You do not have to give up compaction. You have to pick a shape that carries no stale thinking. The documentation names three:
Simple compaction — the recommended one. Replace the entire history with one summary message plus the new user turn, and replay nothing else. No thinking blocks carry over, so nothing can mismatch. The docs note that Claude models are trained on long-horizon tasks with exactly this scheme and that it performs comparably to more elaborate approaches for most workloads. If you are choosing today, choose this.
Keep-tail compaction. If you insist on keeping recent turns verbatim behind a summary, strip the thinking and redacted_thinking blocks from those turns — text and tool calls can stay — or opt into drop_block.
Background compaction. If the summary is built asynchronously and swapped in later, send drop_block on every request that still carries thinking produced before the swap, strip those blocks yourself, or compact synchronously and accept the latency.
The better answer: stop editing on the client
All three shapes above are ways to keep doing the work in the wrong place. The cleaner fix is to move context management to the server, where it doesn't count as an edit at all:
- Server-side compaction (beta header
compact-2026-01-12) summarizes earlier context when the conversation approaches a threshold, and its instructions parameter accepts your own summarization prompt — so you keep editorial control over what survives.
- Context editing (beta
context-management-2025-06-27) clears old tool results or thinking blocks with strategies like clear_tool_uses_20250919 and clear_thinking_20251015.
The reason these are safe is precise and worth internalizing: the history check compares the conversation as you sent it. Anything the server removes after that point cannot invalidate a later thinking block.
One caveat if you adopt server-side compaction: append response.content back to your messages on every turn, not just the extracted text. Compaction blocks in the response are how the API replaces the compacted history on the next request. Pull out the string and append that, and you silently lose the compaction state.
For the mid-session changes you used to make by rewriting the prefix, there are now first-class channels. A role: "system" message appended to messages[] changes instructions without touching the cached prefix. Tool changes go through tool_addition / tool_removal blocks (beta mid-conversation-tool-changes-2026-07-01, with the full tool set declared at session start). Per-turn reminders go in turn-scoped system messages that you leave in the history — they stop rendering after the next user message and cost no tokens once cleared.
That is the mental shift the whole release is asking for: you no longer edit the conversation, you append instructions to it. If your agent architecture treats messages as a mutable buffer you rewrite each turn, that assumption is what needs to change — a design question we spend real time on in the agent architecture course.
The escape hatch, and why it isn't a fix
Send the beta header thinking-binding-controls-2026-08-01 and set prefix_mismatch_behavior to "drop_block" (the default is "error"):
response = client.messages.create(
model="claude-fable-5-1",
max_tokens=16000,
thinking={
"type": "adaptive",
"block_binding": {"prefix_mismatch_behavior": "drop_block"},
},
messages=messages,
)
for t in getattr(response, "input_transformations", []) or []:
if t.reason == "prefix_binding_mismatch":
log.warning("dropped thinking block: %s", t)
Instead of a 400, the API drops the mismatched block and every thinking block after it, reporting each one in the response's input_transformations array with reason: "prefix_binding_mismatch".
Understand the trade. You are not fixing the mismatch, you are discarding the model's preserved reasoning from that point forward and paying for it in quality on exactly the long-horizon tasks you bought Fable 5.1 for. Use drop_block as a shock absorber and a diagnostic — not as your architecture.
The other breaking change in the same release
While you're in the migration, there is a second one that hits a completely different code path. Forced tool choice is gone. Fable 5 accepted tool_choice values auto, none, any, and tool. On claude-fable-5-1, {type: "any"} and {type: "tool", name: "..."} return a 400:
tool_choice: type "tool" and "any" are not supported for this model.
The check applies on the Messages API, the Message Batches API, and the token counting endpoint — so a token-counting call in your cost estimator will fail too, which is a fun way to discover it.
If you used forced tool choice to guarantee structured output, the replacement is {type: "auto"} plus an explicit instruction and strict: true on the tool, or structured outputs via output_config.format. If your application genuinely requires a specific call on the current turn, put the instruction in the user turn or in a mid-conversation role: "system" message. Structured extraction pipelines built on forced tool choice are the most likely thing in your codebase to break on the model ID swap alone — the structured outputs approach is the durable replacement.
A 20-minute audit
Run this before you switch traffic, not after.
- Decide whether you're exposed at all. Does your code construct the
messages array? If a managed harness owns it, you're done.
- Grep for the mutation. Look for anything that slices, pops, filters, or rewrites a messages list; anything that rebuilds
system or tools per request; anything that sorts or serializes tool schemas non-deterministically.
- Turn on enforcement deliberately. Run a representative multi-turn session with
thinking-binding-controls-2026-08-01 and prefix_mismatch_behavior: "drop_block", and log every entry in input_transformations. Each prefix_binding_mismatch is a real bug in your history handling. model_binding_mismatch entries after a deliberate model switch are expected and fine.
- Fix the shape, not the symptom. Move trimming server-side, or adopt simple compaction.
- Freeze the prefix. System prompt and tools set once at session start; every mid-session change goes through a
role: "system" message.
- Replace forced
tool_choice. Including in token-counting calls.
- Pick a production
prefix_mismatch_behavior and monitor it. "error" fails loudly; "drop_block" degrades quietly. Both are defensible — an unmonitored default is not.
- If you ship a framework, test with the field set. Your users' accounts are newer than yours.
Steps 2 and 3 are the ones that find real bugs. Everything else is bookkeeping.
Why this is happening
It is worth understanding the motivation, because it tells you which direction the next release moves.
The ability to hand a model an edited transcript of its own prior reasoning is the core primitive in distillation attacks — you reconstruct a frontier model's reasoning by feeding it modified versions of what it previously produced and observing how it continues. Binding each thinking block to the exact prefix that produced it closes that off without removing the block from the API surface.
It sits alongside the other provenance measure shipped in the same release: models released after 2 August 2026 carry a watermark in their text output — described as a numerical way of determining the likelihood that Claude was involved in writing a piece of text — invisible to anyone without the detection API.
Both point the same way. The frontier vendors are hardening the boundary around model outputs, and the API surface is getting less malleable with each release. Building on the assumption that you can freely rewrite what the model produced is now building against the direction of travel. That is a security and architecture judgement as much as an API one — the kind of reasoning we work through in the AI security course, and in the Claude Code and agentic coding course for teams building harnesses of their own.
The short version
- On Fable 5.1, each
thinking block is bound to the system, tools, and history that preceded it. Edit any of them and the request is a 400.
- Enforced by default for accounts created on or after 31 August 2026. Older accounts are unaffected for now — Anthropic plans to enforce it for everyone on future models.
- If you ship a framework, your users are enforced before you are. Test with
thinking-binding-controls-2026-08-01 and prefix_mismatch_behavior: "drop_block".
- Client-side trimming, keep-tail summaries, background compaction swaps and mid-transcript snipping all break. Simple compaction, server-side compaction, and context editing don't.
- Forced
tool_choice (any / tool) is also gone — a 400, including on token counting.
- Freeze the prefix; append instructions instead of editing history.
If you're planning a context strategy change off the back of this, there's a money-side companion to it: Fable 5.1 also cut cache reads to $0.25/MTok, which makes summarizing-to-save-money a losing trade in most cases. I wrote that up on dev.to as "Fable 5.1 Cache Reads Cost $0.25/MTok." The two decisions interact — the cheap path and the legal path happen to be the same one, which is unusually convenient.
Every behavior, error string, header and date in this article was checked against Anthropic's official documentation on 2 September 2026 — principally the Fable 5.1 migration guide and the preserved thinking guide. Beta headers and enforcement dates change; verify against current docs before shipping.