Max Narditdata & ai systems
← Articles
4 mindev

Claude Fable 5.2's prefix check: a 400 that depends on what your code did last turn

The check that rejects replayed reasoning after an edited history now applies to every account. Code that keeps its history append-only never meets it, and code that doesn't won't find out from a single test request. The fix is in the error message; the hard part is producing the error before production does.

Contents

Claude Fable 5.2 shipped on November 9 at $8 input and $40 output per million tokens, down from Fable 5.1’s $10 and $50 and still twice Opus 5.5’s base rates. Most of what breaks on the switch fails on the first request that touches it. One change fails only on a request that follows an edit to the conversation.

That one is the prefix check. I wrote in September that a 400 is the good kind of break: rejected up front, with the fix in the message. This one has the fix in the message and still passes every fresh single-request test, because it is a property of the conversation, not of the request.

Which Claude Fable 5.2 changes fail on the first request?

Three. Declaring the old computer_20251124 tool returns 400 everywhere except Amazon Bedrock; the replacement is the computer_toolset_20260801 toolset, with its own agent loop. An advisor tool on a Fable 5.2 executor must itself be Fable 5.2 or Mythos 5.2, and its advice comes back encrypted. Coming from Opus 5.5 under zero data retention, every request fails on the Claude API: Fable 5.2 requires 30-day retention unless Anthropic has approved an exception. One more loss has no documented error: in organizations with customer-managed encryption keys, Fable 5.2 has no structured outputs, so the docs say to remove strict: true and output_config.format and validate the output yourself.

When does the Claude Fable 5.2 prefix check fire?

When your code changes the system prompt, the tools or an earlier message, then sends back a thinking block produced after that point. Each block is valid only against the prefix it was generated from. Opus 5.5 and Fable 5.1 return the error by default only for accounts created on or after August 31, 2026; on older accounts the mismatched blocks quietly reached the model. Fable 5.2 returns it on every account. The docs give the error as:

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".

A retry of the same body fails the same way. One exception: in the Message Batches API, an item that leaves the setting unset gets no 400.

If Claude Code, the Agent SDK or Managed Agents builds your requests, nothing changes. Hand-built code is safe if it freezes system and tools for the conversation, only appends to messages, sends each assistant turn back exactly as returned, and avoids the other edits the docs list. Changing effort, max_tokens or cache_control markers is not an edit.

The edits that count are the ones people write to save tokens: memory injected into system on every turn, and client-side trimming of old turns. Swapping tools in and out counts too. Each has a supported replacement: mid-conversation system messages for instructions and tools, server-side compaction for trimming. Two quieter edits show up at the switch itself. An MCP connector server whose tool list isn’t pinned and changes between requests is an edit for Fable 5.2 blocks, though not for Opus 5.5 blocks. And changing the advisor’s model, which the pairing rule forces, is an edit to tools, so make that change in new conversations.

How do you test Claude Fable 5.2’s prefix check before switching?

Replay a real conversation with the check set to report instead of fail. Setting drop_block opts a request into the check on any account, so you can run this against the Opus 5.5 you use today:

python
resp = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=16000,
    system=system,
    tools=tools,
    messages=history,
    thinking={"type": "adaptive",
              "block_binding": {"prefix_mismatch_behavior": "drop_block"}},
    betas=["thinking-binding-controls-2026-08-01"],
)
for t in getattr(resp, "input_transformations", None) or []:
    if t.reason == "prefix_binding_mismatch":
        log.error("invalidated thinking at %s", t.path)

Each prefix_binding_mismatch entry marks a block your code invalidated; the edit sits somewhere before the earliest one. Zero entries mean something only if history actually carried a thinking block back across whatever your code does between turns, so run your real loop long enough for the memory refresh or the trim to fire. With an unpinned MCP connector, repeat the run against claude-fable-5-2, the one case Opus 5.5 can’t show you.

A fresh-conversation canary, like the skeleton in my Opus 5.5 post, cannot exercise this check: there is no earlier turn to edit. That post gave the second turn one sentence. For Fable 5.2 it is the whole test.

In production, keep the default error unless you need drop_block as a stopgap. The docs warn that dropped blocks can raise output tokens.

What does Claude Fable 5.2 change without an error?

Cost, mostly. On the Messages API Fable 5.2 defaults to high effort, where Opus 5.5 defaults to medium, so a request that never set effort runs a level higher at twice the base token price. Unlike Fable 5.1, it keeps thinking at medium and above even when the prompt says “answer directly without deliberating”, so a small max_tokens can end in a thinking block with no text. Anthropic’s own docs say to start most workloads on Opus 5.5 and move up only when your evals at higher effort still fall short.

A router or fallback that moves a conversation from Fable 5.2 to Opus 5.5 or Fable 5.1 drops the Fable 5.2 thinking blocks with a 200, the same binding Sonnet 5.5 introduced.

Is the Claude Fable 5.2 prefix check the right rule?

My read is that the rule is right and the rollout is what hurts. A thinking block replayed against a different history is reasoning about a conversation that didn’t happen, and a 400 is the honest answer. But gating it by account age meant the oldest accounts, the ones most likely to run old hand-rolled history code, hear about it last, and they hear on a model switch.

You probably want the fix anyway. An append-only history is also what lets the prompt cache keep matching from one turn to the next.

01 / Discussion

No comment section here — all discussions happen on X.

Max Nardit@mnardit

02 / More articles