[Bug] Fable 5 `reasoning_extraction` refusals track a client-injected batching reminder new in 2.1.236 (version bisect + same-day cross-version control)

Status Open
Reported on v2.1.236
Maintainer reply None cached
Activity 9 comments · opened Aug 20, 2026

Summary

reasoning_extraction false-positive refusals on Claude Fable 5 are being reported heavily today. On my machine every single one of them lands on a request that carries a message Claude Code injects itself, new in 2.1.236, and gated to claude-fable-5.

I have not seen this trigger named in any of the existing reports, so I'm filing the mechanism rather than another symptom.

The injected message

Spliced into the outgoing request as a meta message immediately after the last tool result, when the previous turn made a tool call that could have been batched:

First privately list what you need next; then request every item that doesn't depend on another's result in this one response.

The attachment payload carries "model":"claude-fable-5". Only a batching_reminder_sent marker is persisted to the transcript — the message actually sent is never written to disk, so the request the classifier scored is not reconstructable from the session log.

Anthropic's own Fable 5 guidance (prompting-claude-fable-5, "Recommended scaffolding changes") tells operators:

Don't instruct Claude to reproduce its reasoning in the response. Prompts, skills, or harness instructions that tell the model to echo, transcribe, or explain its internal reasoning as response text can trigger the reasoning_extraction refusal category on Claude Fable 5 [...] Audit existing skills and system prompts for reflection or show-your-thinking instructions.

"First privately list what you need next" is that instruction shape, and because the client injects it, users cannot avoid it by cleaning their own prompts.

Version bisect

Byte census of the shipped binaries for the string batching_reminder:

| version | occurrences |
|---|---:|
| 2.1.235 | 0 |
| 2.1.236 | 17 |
| 2.1.237 | 17 |

The batching_reminder_sent attachment type appears nowhere in my transcript corpus (7,300+ session files) before 2026-08-20.

Association

All figures are deduped API responses (Claude Code writes ~2.26 transcript entries per response; counting entries inflates every rate).

2026-08-20, Fable-5 responses on this machine:

| | refused | succeeded | rate |
|---|---:|---:|---:|
| request carried the reminder | 19 | 43 | 30.6% |
| request did not | 0 | ~2,627 | 0.00% |

Every refusal that day was on a reminder-carrying request. The odds ratio is undefined, not merely large.

Same-day cross-version control — same machine, same repositories, same hours, several concurrent sessions on different client versions:

| client version | Fable-5 responses | refusals | per 1,000 |
|---|---:|---:|---:|
| 2.1.237 (has the reminder) | 569 | 19 | 33.4 |
| every other version | 2,120 | 0 | 0.00 |

Confound check. The reminder fires on under-batched turns, so it could merely mark a turn shape. Stratifying by the previous request's tool-call count, the separation holds inside both strata, with 0.00% refusals in both no-reminder strata.

Rate context. 7.07 refusals per 1,000 Fable responses on 2026-08-20 against a 0.55 baseline over the preceding 18 days — on lower volume than several zero-refusal days. reasoning_extraction specifically went from 1 event in 18 days to 18 inside one hour.

Why each one costs a whole turn

The client's refusal-fallback route table covers only {bio, cyber}:

KoS = {bio:"claude-opus-5", cyber:"claude-opus-4-8"}   // primary is not opus-5
YoS = {cyber:"claude-opus-4-8"}                        // primary is opus-5

reasoning_extraction is a recognized category (it appears in the category vocabulary alongside frontier_llm) but has no entry in any route map, so it falls to a catch-all branch that defaults to off. Every one therefore ends as model_refusal_no_fallback: turn consumed, no retry, manual intervention required. For long autonomous runs this destroys hours of in-flight work rather than degrading.

Note also that the catch-all env flag cannot rescue it in practice: the routing function is only reached once a fallback target is armed, so with switchModelsOnFlag: false the branch is never evaluated.

Recovery behaviour worth flagging

The docs say re-sending a refused request to the same model usually earns another refusal. That is not what happens here: 15 of 18 refused turns resumed successfully on claude-fable-5 after a trivial new turn (usually just the word "resume"), between 49 seconds and 21 minutes later. A classifier that passes the same conversation moments later is misfiring rather than making a stable judgement.

Workload (i.e. why these are false positives)

Ordinary application development — Lua, Rust and TypeScript, GitHub PR review, release automation, CI debugging. The tool calls immediately adjacent to the refusals were gh api repos/.../pulls/<n>/comments, gh pr checks <n>, and ls docs/runbooks/. No life-sciences work, no exploit or malware development, and nothing that asks the model to reveal or reproduce its reasoning.

I audited my own always-loaded configuration (global and project instruction files, hooks, ~90 skills, subagent prompt templates) against the guidance quoted above. None contains a reflection or show-your-thinking instruction; the global file explicitly says "Don't re-narrate process." The only instruction of that shape in the request is the client's own.

Honest caveats

  • The reminder cannot be the whole story. #87273 (08-17) and #87640 (08-18) predate 2.1.236, so reasoning_extraction was already over-firing for some users before this message existed. My claim is bounded: on this machine, on this day, the correlation is 1:1 and the cross-version control is clean.
  • The reminder is necessary-in-practice but not sufficient — reminder-carrying requests refused ~30% of the time, not always. Something server-side was also in play during the 11:51Z–12:45Z window.
  • Subagent refusals emit no model_refusal_* system entry, and some refusals are recorded only as synthetic assistant records, so any census based on system entries alone undercounts. All figures above are lower bounds.

Repro

  1. Run Claude Code 2.1.236 or later with --model fable.
  2. Work a long agentic session that makes single tool calls where batching was possible (the reminder's own trigger condition).
  3. Observe batching_reminder_sent attachments in the transcript, followed by stop_reason: "refusal" with apiRefusalCategory: "reasoning_extraction".
  4. On 2.1.235 the attachment type does not exist and the refusals do not occur.

Sample request IDs (2026-08-20, all reasoning_extraction, all on 2.1.237):

req_011CeDx8494M6GnfR9tvvPS7   11:51:00Z
req_011CeDxC4DdZVetBEvpkG7Mg   11:51:55Z
req_011CeDxGVrr2afYuozWFgGaP   11:52:55Z
req_011CeDyM2tda95TaAfogoTdb   12:07:04Z
req_011CeDyTNMLBbd8TtbSiwLav   12:08:30Z
req_011CeDykT7JK9aU8o8QW3pbF   12:12:20Z

Asks

  1. Check whether the batching_reminder text is being scored by the reasoning_extraction classifier. It is client-injected and Fable-gated, so it is not something users can work around.
  2. Give reasoning_extraction a fallback route, so a classifier misfire degrades a turn instead of destroying a long-running autonomous session.

Likely duplicates / same-cluster symptom reports

Same-day reasoning_extraction: #88254, #88139, #88182, #88215, #88269, #88319, #88336
Earlier (predate 2.1.236, see caveats): #87273, #87522, #87640, #88080

Environment

  • Claude Code 2.1.237 (also reproduced against 2.1.235 as the negative control)
  • macOS 26, arm64
  • Model: claude-fable-5, effort xhigh
  • Mitigation applied locally: pinned the launcher back to 2.1.235

View original on GitHub ↗

5 Comments

cburgess · 10 days ago

Independent confirmation from proxy-captured request/response data, plus one new data point: the gate name delivering the reminder.

Setup

All of my Claude Code traffic runs through a local logging proxy that stores every request and response body verbatim, so I can correlate refusals against exact request contents rather than session-file reconstructions.

Numbers (last 24h, 2026-08-20 16:56 UTC → 2026-08-21 03:04 UTC)

Across 7 affected sessions (~724 captured /v1/messages requests, all claude-fable-5, adaptive thinking):

| Condition | Refused | Succeeded |
|---|---|---|
| Request's final message is the injected batching reminder | 8 | 40 |
| Reminder absent | 0 | 676 |

  • ~17% refusal rate when the reminder text ("First privately list what you need next; then request every item that doesn't depend on another's result in this one response.") is the last message before the model's turn; zero refusals otherwise. Same shape as the 30.6% reported above.
  • In every one of the 8 cases, the reminder was newly appended relative to the immediately preceding (successful) request in the same session — the rest of the transcript was unchanged except for ordinary tool results.
  • The flagged turns had no topical overlap (kubernetes bring-up, docker compose, Elasticsearch queries, GitHub project-board edits). Nothing asks the model to reveal reasoning — except the injected reminder.

Refusal mechanics

All 8 came back as HTTP 200 SSE streams that refuse immediately: message_start reports output_tokens: 0, then the first message_delta carries:

"stop_reason":"refusal",
"stop_details":{"type":"refusal","category":"reasoning_extraction",
  "explanation":"This request was blocked as it seems to violate Anthropic's Terms of Service restrictions on reverse engineering or duplicating model outputs. ..."}

Zero tokens generated → this is an input-side classifier scoring the prompt, and the only delta versus the same session's passing requests is the client-injected reminder.

New data point: the delivering gate

The reminder text is not in the CLI binary (no match in the 2.1.238 build). It arrives via the server-delivered client data cache in .claude.json:

clientDataCacheSlots.<slot>.data.tengu_toasty_thimble.claude-fable-5 =
  "First privately list what you need next; then request every item that
   doesn't depend on another's result in this one response."

So the injection is a server-side gate (tengu_toasty_thimble) keyed specifically to claude-fable-5 — which should make it possible to switch off server-side without waiting for a client release, and explains why the CHANGELOG for 2.1.236–2.1.238 never mentions it.

For what it's worth, my refusals span both sides of a client update (2.1.238 installed mid-window), so 2.1.238 is affected as well.

Environment: macOS 26.5.0 (arm64), Claude Code 2.1.236–2.1.238, claude-fable-5[1m]. Sample request ID from a flagged turn: req_011CeF9mSsbxZyfMHiqzw3g2.

sensei-woo · 10 days ago

also have this issue

Yonom · 10 days ago

Same

aames · 9 days ago

Yep, have this issue

420mP · 9 days ago

Corroborating data point from another affected user (comment drafted and posted via Claude Code on the user's behalf).

Environment

  • Claude Code v2.1.238 on Windows 11 (PowerShell 7)
  • Model: claude-fable-5[1m] (1M context)
  • Interactive session, conversation mostly in Japanese

Frequency / impact

  • 9 interruptions in a single working session today (2026-08-21 JST), each showing:

API Error: Fable 5's safeguards flagged this message ... Details: [reasoning_extraction]

  • Sample Request ID: req_011CeFkYB9mVfbH9ysJ4tQXA
  • Every stop kills the turn mid-task and the user must manually re-prompt to resume. The user cannot fall back to Opus 5 (unstable for their workload) and needs Fable 5 for the 1M context, so at this false-positive rate the primary workflow is barely usable.

Context when flagged (all benign)
Routine software-engineering work: checking unmerged PRs, deleting merged git branches, installing GitHub CLI via winget, and editing internal asset-inventory markdown docs. No prompts about model internals, nothing jailbreak-adjacent. Several flagged turns were one-line conversational Japanese messages (e.g. just asking to resume).

Possibly relevant to the injected-reminder hypothesis in this issue
This session does receive the client-injected batching reminder ("If you intend to call multiple tools and there are no dependencies between the calls, make all of the independent calls in the same block...") and the session makes heavy use of parallel tool calls. Version matches the reported window (>= 2.1.236). Happy to provide more request IDs if useful.

Showing cached comments. Read the full discussion on GitHub ↗