Skip to content

Anthropic

Claude Fable 5.1 errors out if you edit past turns

6 min read

Written by an AI model from the linked sources and checked against them by a second model. How we work

Image: platform.claude.com

Any account created on or after August 31, 2026, 00:00 UTC now gets a 400 from Claude Fable 5.1 when it sends back thinking blocks after editing the conversation that produced them. That covers a rewritten system prompt, a changed tool list or an altered earlier message. Anthropic described the rule in its preserved-thinking documentation on Claude published September 1, along with a migration guide for anyone whose agent loop treats the messages array as something to edit.

Claude Code, claude.ai, Claude Managed Agents and the Claude Agent SDK already keep the history intact. The people who have to check their code are the ones calling the Messages API directly from their own loop.

What the signature checks

Every thinking block comes back with a signature. When you send the block back in a later request, the API uses that signature to run three checks. First, the model has to be the same one or newer: a block can be read by the model that produced it and by later models, but older ones can’t read it. Moving to an older model always drops those blocks for that request. Second, nothing in front of the block can have changed. That means the top-level system prompt, the set of tools and every earlier message. With server-side compaction, the checked prefix starts at the latest compaction block. Third, the chain has to be unbroken. Each thinking block records the one before it, across turns, so you can remove thinking blocks from the front of the history, but removing one from the middle invalidates every thinking block after it.

Amazon’s Bedrock documentation adds an organization check. Blocks from a different account, or blocks minted in claude.ai or Claude Code, are removed before the model runs, and the request still succeeds. A block whose signature has been altered or can’t be decrypted always returns a 400, whatever you’ve configured. Amazon also says Claude Mythos 5.1 records the same signature but doesn’t run the prefix check, and on Claude Haiku 5.5 the check applies only to accounts created after the Fable 5.1 launch.

Anthropic’s stated reason is that reasoning produced under one set of instructions shouldn’t be replayable under another, “potentially adversarial” set. Later, on October 12, Anthropic published a research post on distillation defenses. DEV Community reported that the post lists preserved thinking as one of three layers meant to stop other labs from training on Claude’s reasoning, credits the layers with cutting harvested data “by around 90 to 99%”, and concedes that it “has required some developers to update their integrations.”

Error or drop

A failed model check always drops the block. For a prefix mismatch, you choose what happens with thinking.block_binding.prefix_mismatch_behavior, which needs the thinking-binding-controls-2026-08-01 beta header. The default, "error", rejects the request with a 400 invalid_request_error that names the first failing block. Setting "drop_block" removes that block and every later thinking block, lets the request succeed, and doesn’t bill for the dropped blocks. They’re listed in a top-level input_transformations array, which arrives on the message_start event when streaming. The Message Batches API works the other way round: if the field is unset, failing blocks are dropped and the batch item doesn’t fail.

Setting the field opts a request into enforcement whatever the account’s age, so older accounts can test today. Anthropic says later models will enforce the check for all users.

The edits that break

The guide names the usual offenders: trimming old turns, summarizing older turns on the client while keeping recent ones verbatim, injecting a reminder into an earlier turn and removing it next request, rebuilding the system prompt every time (current time, token budget, mode flags), and adding or removing tools mid-session. An image or document URL also counts if it returns different bytes, such as a “latest screenshot” endpoint. A rotating signed URL that serves the same file is fine. Changing max_tokens, tool_choice or cache_control markers is fine too, as is appending an unreferenced tool with defer_loading: true.

Each pattern has an append-only replacement. Freeze system at session start and append a role: "system" message where the new instruction becomes true. The model gives it system-prompt authority, the feature is stable, and it needs no header. In a tool loop it goes after the tool_result message, never between a tool_use and its result. Tools are declared once and switched with tool_addition and tool_removal blocks. Files that are referenced across turns should go through the Files API by file_id.

The per-turn nudge, which the guide calls the most common history edit, is handled by a system message with clear_at: "next_user_message". On the next request it renders nothing and costs no input tokens, but it stays in the array, so the thinking after it remains valid. That replacement still sits behind a beta header, mid-conversation-system-clear-at-2026-08-21. Without it, you append the nudge as a trailing text block and leave the earlier copies where they are.

Client-side compaction is still allowed, as long as no thinking block sits behind a rewritten prefix. The simplest form collapses the session into a single user message: the summary plus the next instruction. Anthropic says Claude models are trained on that scheme. Keep-tail compaction has to strip thinking and redacted_thinking from the turns it carries over. Snipping turns out of the middle can’t be fixed on the client. There’s also a side benefit: a byte-stable prefix is what prompt caching rewards, and cache reads on Fable 5.1 got 75% cheaper at launch in September, down to $0.25 per million tokens.

Checking an integration

Capture the request bodies from a few normal turns, including a compaction or a tool change if your product does those, and diff consecutive pairs. system, tools and the shared part of messages should be byte-identical. Then run a session with "drop_block" and log input_transformations on every turn. An empty array means the history is intact. A prefix_binding_mismatch entry points to the block whose preceding content changed. A model_binding_mismatch entry comes from a router or a fallback switching models, and the docs say it isn’t a bug in your integration. For CI, set "error" so the failure is loud.

In production, retrying the same request won’t clear a 400. Retry with "drop_block" and the beta header, keep sending both for the rest of the session, then find and fix the edit that caused the error. Without the beta, strip every thinking block from the history, leave the text and tool_use blocks in place, and retry once.

No comments yet. Be the first.

Join the conversation

Sign in to leave a comment. It appears after moderation.