[BUG] Fable 5: mid-turn assistant text blocks intermittently delivered as summarized thinking blocks (turn appears silent)

Status Open
Reported on v2.1.201
Maintainer reply None cached
Activity 22 comments · opened Jul 5, 2026

Environment

  • Claude Code: 2.1.201
  • Model: claude-fable-5
  • Platform: Linux (WSL2), Anthropic API (subscription)
  • Observed both in the on-disk transcript (~/.claude/projects/**/<session>.jsonl) and in a --output-format stream-json consumer rendering the same stream

Summary

On Fable 5, when the model emits thinking → text → tool_use within a turn, the client intermittently never receives the text block. Instead it receives an extra short thinking block, with a valid signature, whose content is a paraphrase of the missing user-facing text — i.e. the summarized-thinking pipeline appears to absorb the model's text block into the thinking summary stream.

Because Claude Code hides thinking by default, affected turns look completely silent: the model works through tool calls with no visible narration, and text clearly written for the user (status updates, sometimes even instructions) is only discoverable by expanding thinking blocks in a client that renders them.

Evidence

From one session (4a80f3d4-eb8a-4e4b-b791-9efa8bd31171), block composition per assistant message id:

msg_01RGLsVsMqW1fTGEDHuMRExz ['thinking', 'text', 'tool_use']   <- text delivered (ok)
msg_01X1PEtb6xF27hJuFHwmBTUm ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_013UEULaCURMbNGfpWYLazSL ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_01CDBLob3BAqEb6u25XB47vS ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_017k9JmCVezg4Vt4YAMALSk2 ['thinking', 'thinking', 'tool_use'] <- text swallowed
msg_015ggGe2xFVcFCS7LT7W7sVW ['thinking', 'text', 'tool_use']   <- text delivered (ok)
msg_019JkXNVEyRcKPbgQY42Vevn ['thinking', 'thinking', 'tool_use'] <- text swallowed

Example (msg_01X1PEtb6xF27hJuFHwmBTUm, requestId req_011CcjR4DNPhEkZKdZBWafVA, 2026-07-05T18:52:50Z):

  • The model's intended user-facing text for that turn (confirmed because the model quotes it verbatim in later turns — it exists in the model-side conversation) was:

> "You caught a live specimen — this very session. Let me look at the raw transcript on disk to see what those two blocks actually are on the wire."

  • What the client received instead was a second thinking block (88 chars, signed):

> "I'll check the raw transcript to see what those two blocks actually contain on the wire."

  • The verbatim text appears nowhere in the stream or transcript (grep -c "live specimen" <transcript> → 0), while the paraphrase arrived typed as thinking.

The paraphrase-not-verbatim relationship (same content, different, shorter wording) is the fingerprint of the thinking summarizer, and the valid signature on the block means it was typed as thinking server-side — the client cannot mint signed thinking blocks, so this is not a client-side mislabeling.

Expected

Assistant text blocks are always delivered to the client as text content blocks, regardless of the thinking display mode. The thinking summary should cover only the chain of thought, not absorb the model's user-facing output.

Impact

  • Fable 5 frequently appears to "go silent" in Claude Code — long tool-calling stretches with zero visible narration, because the narration was emitted but delivered as hidden thinking.
  • User-directed content (including, occasionally, instructions the model wants the user to follow) lands in thinking blocks the default UI never shows.
  • Clients that do render thinking (custom stream-json consumers) show a confusing "double thinking block" pattern where the second block reads like it was addressed to the user — because it was.

Frequency

5 of 7 text-bearing tool-calling turns in the session above. Intermittent within a single session, so unlikely to be a per-request configuration difference.

Related (distinct) issues

  • #21751 — assistant text missing from transcript persistence (text was received but not written). Different failure: here the text never arrives on the wire at all, and a signed thinking paraphrase arrives in its place.
  • #66887 — Fable 5 thinking blocks render as empty stubs in the VS Code extension (display/omitted rendering issue, not content misrouting).

View original on GitHub ↗

22 Comments

carrotRakko · 3 months ago

Can confirm, with corpus-scale numbers. I grouped assistant JSONL entries by message.id and counted block-sequence shapes per API response.

Corpus, to be precise about scale: 788 transcript files under ~/.claude/projects/**/*.jsonl — that is 154 main sessions + 634 subagent transcripts, mixed CLI versions up to 2.1.201, and mixed models, so the per-model response counts below are the meaningful denominators. The Fable 5 portion is 5,908 API responses across 38 files. Non-Anthropic models present in the corpus were excluded from the comparison.

Rate

Among Fable 5 responses that continue after a tool result and carry a mid-turn note, the note lands in a second thinking block more often than in a text block:

| shape | count |
|---|---|
| [thinking, thinking, tool_use, …] (note swallowed) | 1,688 |
| [thinking, text, tool_use, …] (note delivered) | 1,402 |

That is ~55% of mid-turn narration never surfaces as text (1,688 of 5,908 total Fable 5 responses, ~29%, are the swallowed shape). The pattern is strikingly regular: always exactly two thinking blocks, never three or more (0 occurrences), and the second one is short (median ~91 chars displayed) and stylistically identical to the text blocks in the delivered variant — a one-or-two-sentence status update ("X is done, checking Y next").

Cross-model comparison (same corpus, same method)

| model | responses | […, thinking, thinking, …] |
|---|---|---|
| claude-fable-5 | 5,908 | 1,688 (29%) |
| claude-opus-4-7 | 13,082 | 0 |
| claude-opus-4-8 | 480 | 1 — dated 2026-06-09 |
| claude-haiku-4-5 | 56 (subagent turns only) | 0 |

The single Opus 4.8 occurrence predates the fix referenced in #74176 (#66112 was the Opus report, now closed); after that date my Opus corpus is clean while Fable 5 reproduces daily. This independently corroborates "fixed for Opus, still broken on Fable".

Two further observations

  1. Expanding thinking does not recover the original text. The displayed thinking is the summarized form, so even clients that render thinking show a paraphrase of the swallowed note rather than the note itself. In one of my sessions a Japanese status update surfaced as a shorter English summary; in another, a casual first-person sentence was displayed as a terse third-person rewrite. The user-facing words are not recoverable from any client surface.
  2. The model's self-model treats the note as delivered. When later asked what it had reported, the model quoted the swallowed notes verbatim as things it had "said to the user", matching the behavioral evidence in #74176. So instructions like "give brief status updates between tool calls" are, from the model's point of view, being followed — the content just never leaves the thinking channel.

Repro / measurement

Anyone can measure their own rate:

import json, glob, os, collections
seqs = collections.Counter()
for f in glob.glob(os.path.expanduser("~/.claude/projects/**/*.jsonl"), recursive=True):
    resp = {}
    for line in open(f, errors="replace"):
        if '"assistant"' not in line: continue
        try: e = json.loads(line)
        except ValueError: continue
        if e.get("type") != "assistant": continue
        m = e.get("message") or {}
        if m.get("model") != "claude-fable-5" or not isinstance(m.get("content"), list): continue
        resp.setdefault(m["id"], []).extend(b["type"] for b in m["content"])
    for types in resp.values():
        seqs[tuple(types[:3])] += 1
print("swallowed:", seqs[("thinking", "thinking", "tool_use")],
      "delivered:", seqs[("thinking", "text", "tool_use")])

Related: #74176, #66112 (Opus, closed), #65620, #74260 (possibly the same root cause observed from the rendering side).

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

abdulrehman-11 · 2 months ago

Independent reproduction and extended characterization — Windows 11, Claude Code 2.1.212, claude-fable-5, Anthropic API, xhigh effort. Same persisted fingerprint as the OP: ['thinking','thinking','tool_use'] where ['thinking','text','tool_use'] was emitted, second thinking block validly signed, text block absent from the wire and from the session .jsonl.

We ran 44 controlled tests (unique token + 5 marker lines per probe, visibility confirmed by a human each run, then cross-checked against the session file). Findings:

The behavior is purely positional within a turn:

| Position of assistant text | Result | Controlled record |
|---|---|---|
| First text block of the turn (before any tool call) | renders | 14/14 (incl. 6/6 directly before AskUserQuestion) |
| Mid-turn (after any tool result, before the next tool call) | absorbed | 18/18 lost |
| Final text block of the turn (nothing after it) | renders | 100%, incl. a >2K-token block |

Ruled out by direct test:

  • Text length: a ~35-character mid-turn one-liner was absorbed.
  • The following tool: Bash vs AskUserQuestion — identical. "Anchoring" the text to an immediately-following trivial tool call, double anchors, and sandwiching the text between two tool calls all failed; the persisted sequence shows the text was adjacent to tool_use on emission and still vanished.
  • Renderer: default and fullscreen TUI behave identically (transcript mode also lacks the text — it's absent from the data, not the paint).
  • Client environment: no hooks matching the tools involved, stock binary across three auto-updated versions, reproduced fresh each time.
  • Model control: Opus 4.8 is immune — 2/2 clean on the exact shape (tool_result → text → tool_use) that failed 18/18 on Fable 5 in the same session. Consistent with the summarized-interleaved-thinking pipeline being the locus.

Severity note: this is data loss, not a cosmetic issue. The absorbed text is absent from the session .jsonl, so --resume, compaction, and /export permanently lose it — including for the model, whose context is rebuilt from that file. Higher effort levels amplify the trigger rate (more interleaved thinking → more text → thinking adjacencies), which may explain why reports are rare: at default effort the turn merely looks "quiet" occasionally.

Workaround (validated end-to-end, incl. a >2K-token payload and a timer expiring mid-stream): keep user-facing text out of mid-turn positions, and use background-task auto-resume as a turn splitter when text must precede a tool call after other tool use. Exact snippet we now carry in the global CLAUDE.md:

### FOR FABLE MODELS ONLY — mid-turn text absorption (non-Fable models: skip this entire subsection)

This subsection, including every numbered rule inside it, applies ONLY when the running model is a Fable model. (Verified 2026-07-18, 44 tests; upstream anthropics/claude-code#74558; server-side, unfixable client-side.)

Fable's thinking-summarizer absorbs any assistant text emitted between a tool result and the next tool call — the user never sees it (18/18 in controlled tests, regardless of length or which tool follows). Only a turn's FIRST text block and FINAL text block render reliably. AskUserQuestion's own question/option text always renders. When running as Fable, follow these rules (no other model may adopt them):

1. Never emit user-facing text between tool calls. Everything the user must read goes in the turn's first text block or its final text block; restate in the final block anything accidentally narrated mid-turn.
2. Explain-then-ask in a fresh turn (no tool calls yet): write the explanation, then call AskUserQuestion — turn-initial text is safe.
3. Explain-then-ask after any tool use (mid-turn): use the **timer-split** — (a) arm `sleep 2; echo "timer done"` via Bash `run_in_background: true` BEFORE writing anything user-facing, (b) end the turn with the explanation as the final text block, (c) when the task notification auto-resumes, open the fresh turn with AskUserQuestion directly (no text before it). Never write text after arming — it becomes mid-turn text and dies.

The ordering constraint in rule 3 is load-bearing and was verified separately: text emitted before arming the timer is mid-turn text and is absorbed; armed-first with the text as the turn's final block survives every time.

Happy to provide the full per-test log (tokens, persisted block sequences, message IDs) if useful.

rbardak · 2 months ago

+1 I am also affected by this issue. It seems to be getting worse. Just now, I had fable run a full implementation task on a ticket, and all I saw was

me: /layered-build implement COP-82
Fable: alright I will load the skill first.
...
about 15 tool calls with absolutely no messages
...
Fable: Task completed, submitting close-out commit.

That was it - and after asking what was going on, Fable reported that it had indeed sent walls of text and in-turn status updates to me - they never showed up in the TUI.

yuanzhi1203 · 2 months ago

This is a server side behaviour called connector text summarization, only described in https://docs.aws.amazon.com/bedrock/latest/userguide/claude-messages-adaptive-thinking.html

Here are some details about an experiment around it: https://matrix.dev/blog-2026-06-10

UNIVAC-Colonel-Panic · 2 months ago

Adding independent confirmation with evidence at two layers, including a terminal byte-capture.

Environment

  • Claude Code 2.1.220, macOS (darwin), model claude-fable-5
  • Viewed over SSH from a Windows terminal client (AbsoluteTelnet) — relevant only because the client's session logging gave us a raw byte capture of everything the TUI wrote to the terminal

What we saw

3-for-3 reproduction with this turn shape: a long multi-paragraph markdown text block (bold, numbered list, inline code) emitted between two Bash tool calls — i.e. thinking → tool_use → [text] → tool_use → text. The bracketed mid-turn text block silently never appears; text before the first tool call and after the last tool call renders normally. The same content re-emitted later as an end-of-turn message renders fine.

Where the missing narration should have been, the UI showed only a thinking spinner summary ("Cogitated for 36s").

Initially we suspected the terminal client was dropping the text (it had a history of rendering issues since fixed), so we captured client-side logs during two deliberate repro runs — one with a mid-turn user message injected, one without (both swallowed; mid-turn input ruled out as a trigger).

Evidence

  1. Terminal byte capture (client session log, raw stream incl. escape sequences): zero bytes of the missing text block in either run's capture, while every piece of text that did render on screen is present. The TUI never wrote the block to the terminal.
  2. On-disk transcript (~/.claude/projects/**/<session>.jsonl): the missing blocks appear nowhere as content (verified with self-contamination-proof greps — patterns like control can procee[d] so the probe can't match its own tool-call echo). Delivered text blocks from the same turns are present as normal text content.

So the block was absent from the wire, not mis-rendered — consistent with the OP's finding that the text is absorbed server-side into the summarized-thinking stream (our spinner-summary observation matches the "signed thinking paraphrase" fingerprint).

Repro recipe that hit 3/3 for us

Ask for a turn structured as: short text → tool call (a few seconds) → long formatted text block (bold + numbered list + inline code, ~1–2 KB) → another tool call → short closing text. In our sessions the mid-turn block was swallowed every time with this shape, while dozens of ordinary turns with short mid-turn status lines rendered fine — suggesting long/formatted mid-turn text blocks (or the amount of preceding thinking) raise the absorption probability well above the OP's "intermittent".

williamrobotma · 2 months ago

v2.1.220 repro with a 4-model control experiment: the text loss is Fable-only.

Setup

  • Claude Code: 2.1.220 (current release)
  • API: Anthropic
  • OS: Linux (WSL2), fullscreen terminal UI
  • Constant: single session throughout; only /model changed between runs

Method

  1. Per run: emit 3 uniquely-worded one-line marker texts inside one turn, at fixed positions:
  • A - start of turn, before the first tool call
  • B - mid-turn, between two tool calls
  • C - immediately before an AskUserQuestion tool call
  1. Record which markers display live in the terminal.
  2. Grep each marker's unique wording in the transcript: ~/.claude/projects/**/<session>.jsonl.
  3. Compare displayed vs stored, per marker.

Results

| Run | Model | Effort | A (start) | B (mid) | C (pre-question) |
|---|---|---|---|---|---|
| 1 | claude-fable-5[1m] | xhigh | delivered | lost | lost |
| 2 | claude-sonnet-5 | xhigh | delivered | delivered | delivered |
| 3 | claude-fable-5[1m] | xhigh | lost | lost | lost |
| 4 | claude-opus-4-8 | xhigh | delivered | delivered | delivered |
| 5 | claude-opus-5 | xhigh | delivered | delivered | delivered |
| 6 | claude-fable-5[1m] | low | lost | lost | lost |
| 7 | claude-fable-5 (no 1m) | xhigh | delivered | lost | lost |

Legend

  • delivered = displayed live, and present in the transcript file
  • lost = not displayed, and absent from the transcript file

Findings

  • Fable, mid-turn markers (B + C): 8/8 lost
  • Fable, start-of-turn markers (A): 2/4 lost
  • Sonnet 5 / Opus 4.8 / Opus 5, all positions: 9/9 delivered
  • End-of-turn text, all models, entire session: 0 lost
  • Display-vs-storage agreement: 21/21 markers - every marker that displayed was stored,

every marker that didn't display is absent from the file; the renderer is exonerated,
lost text never reached the client

  • [1m] long-context flag: no effect - loss identical with and without it
  • Effort level (xhigh vs low): no effect - loss identical at both

This issue's open questions

  • Other models affected? No - Fable-only under this procedure
  • Effort correlation? None - see Findings
  • Thinking correlation? Confounded - Fable's stream carried many thinking blocks during

the runs, Sonnet/Opus near zero; "Fable the model" vs "active thinking summarization"
is not separable from this data

  • Summarized-thinking substitution? Not reproduced - zero paraphrases of any lost marker

found in any stored thinking block; the lost text left no trace

  • Caveat: this transcript stores one content block per line, so in-message block order

(the [thinking, thinking, tool_use] fingerprint) was not checkable

Notes

  • Billing: lost text was generated and billed, but never delivered - same complaint

as #64129

  • #74260: likely the same failure class; refinement from this data - mid-turn text

before a following tool call survived 0/8, end-of-turn text survived 100%

  • Available on request: full session transcript, exact marker wordings, timestamps

Drafted by Claude Fable 5 (the affected model), directed and reviewed by the reporter, who performed all observations.

DannyGelf · 2 months ago

Confirming on macOS (Darwin 25.5.0), VSCode 1.131.0, extension anthropic.claude-code 2.1.220 (also observed on 2.1.207), CLI 2.1.197, model claude-fable-5.

Mid-turn assistant text blocks — text emitted between tool calls within a single turn — never render in the extension UI. They collapse under "Thought for Xs" rows (frequently a "Thought for 0s" entry with nothing expandable). Only turn-final text and AskUserQuestion dialog contents render visibly.

Hit in two separate sessions on the same day (2026-07-31). In one, a multi-section review report plus a rationale paragraph before each of four consecutive AskUserQuestion calls were all invisible — I answered the questions without ever seeing the context that preceded them. The same interaction patterns render fine with Opus models in the same extension.

Happy to provide session JSONL excerpts if useful.

kennedybaird · 1 month ago

Confirming this is still present on 2.1.238 (also reproduced on 2.1.222), in headless --print mode with --output-format stream-json — so it's not a TUI rendering issue.

Setup: Claude Fable 5 with interleaved thinking, running via claude --print from a bridge that forwards output to a chat surface. We tap raw stdout at the stream-json layer, so we capture every emitted event verbatim.

Repro: deterministic for us. When the model writes assistant text between tool calls (after a tool result, before the next tool_use), that text is never emitted. Concrete captured example — the full assistant event sequence for one affected turn (content redacted to types/sizes; this is from the stream-json stdout capture, and the session transcript JSONL is byte-identical for these blocks):

event  1: assistant  tool_use (mcp tool)
event  3: user       (tool result)
events 4-9: system   thinking_tokens  ×6      ← model spent substantial thinking budget here
event 10: assistant  thinking: len=0, signature_len=1468   ← EMPTY thinking text, signed
event 11: assistant  thinking: len=0, signature_len=2736   ← EMPTY thinking text, signed
event 12: assistant  tool_use (Bash)
event 13: user       (tool result)
event 14: assistant  text: len=101   ← only a 1-sentence stub survives
event 15: result     subtype=success, result = same 101-byte stub

The user's question required a substantive multi-part answer; the model demonstrably generated it (six thinking_tokens events, then two thinking blocks carrying 1.5KB/2.7KB signatures over zero bytes of visible thinking text), but the mid-turn text block never appears — not in stream-json stdout, not in the transcript JSONL, not in the final result field. The user then had to ask for a resend. This is data loss at emission time; downstream consumers cannot recover it.

Boundary observation that may help narrow it down: text written before the first tool call of a turn and the final text block of a turn are always delivered. Only interior slots (post-tool-result, pre-next-tool-call) are affected, and only with interleaved thinking. The empty-but-signed thinking blocks suggest the text is being folded into thinking content that's then redacted/encrypted.

Likely the same underlying bug as #74260 (the followed-by-more-thinking variant) — the two look like one emission-ordering issue viewed from either side.

aultra · 1 month ago

The absorbed block identifies itself: its signature carries the label narration instead of thinking.

This thread already establishes the shape (['thinking','thinking','tool_use'] where ['thinking','text','tool_use'] was emitted) and that the second block is validly signed. Adding one detail I haven't seen mentioned, which turns the shape heuristic into an exact discriminator: the label is readable client-side, in the persisted transcript.

Thinking blocks persist locally with thinking: "" but an intact signature. Base64-decoding the signature and scanning its leading bytes yields a literal type token — thinking on ordinary reasoning blocks, and narration on the blocks that absorbed user-facing text.

import base64, re

def signature_label(sig):
    """-> 'thinking' | 'narration' | None, from a thinking block's signature."""
    for cut in (len(sig), 400, 200, 120):
        chunk = sig[:cut]
        chunk += "=" * (-len(chunk) % 4)
        try:
            raw = base64.b64decode(chunk, validate=False)
        except Exception:
            continue
        m = re.search(rb"(?:thinking|narration)", raw[:200])
        if m:
            return m.group(0).decode()
    return None

Corpus result

Across 133 transcripts / 38,322 assistant messages (Claude Code 2.1.241, macOS, claude-fable-5):

| signature label | count |
|---|---|
| thinking | 19,838 |
| narration | 2,359 |

All 2,359 narration-labelled blocks sit in a message that contains no text block and at least one tool_use. Zero counterexamples. Distribution of those messages:

1817  ['thinking', 'thinking', 'tool_use']
 262  ['thinking', 'thinking', 'tool_use', 'tool_use']
 128  ['thinking', 'tool_use']
  74  ['thinking', 'thinking', 'tool_use', 'tool_use', 'tool_use']
   …

Note the 128 single-thinking cases: the double-thinking shape is not a reliable signal on its own — the label catches absorptions that shape-matching misses.

For rate: on the 12 most recent transcripts, 2,083 messages carried a healthy thinking → text → tool_use against 517 with the no-text shape — so roughly one in five messages that should have carried narration lost it.

Why this matters beyond diagnosis

  1. It is a server-side discriminator, not an inference. Anything built on message shape has a false-positive rate; this doesn't. We shipped a Stop hook on it that asks the model to restate absorbed narration as turn-final text, and it needs no heuristics — a prior attempt here that guessed from shape produced ~45 false reprints of text the user had already read.
  2. It suggests the typing decision is made somewhere that still knows the block was narration. If the label survives into the signature, the block was categorised correctly and then emitted with the wrong type — which may narrow where the fix belongs.
  3. It gives a regression metric. Counting narration labels per session is a cheap, objective measure of whether a fix landed.

Impact worth restating

Because Claude Code hides thinking, an absorbed block is completely invisible: not on screen, not in the transcript text blocks, and not in any tooling that archives assistant prose by reading text blocks. Users experience it as the assistant going silent for long tool-calling stretches, or — the worst case — as a question arriving with none of the explanation that was written for it moments earlier.

Happy to run further queries against this corpus if a maintainer wants a specific cut.

glen-84 · 1 month ago

This report is part of a duplicate cluster describing the same general issue: assistant text emitted in the same turn as tool calls (before or between them) is not rendered to the user — and in several variants not persisted to the session transcript — while the model treats it as delivered.

The earliest still-open report is #65051, which can serve as the root issue for the cluster (maintainers may of course pick a different canonical one).

_Drafted by Claude (Anthropic AI assistant)._

yordanove · 1 month ago

Happens to me as well - constantly getting "(summarized)" with greyed-out text even when all the settings are set appropriately. This really pollutes the transcript

<img width="1478" height="121" alt="Image" src="https://github.com/user-attachments/assets/fac990a4-df0e-4045-955a-0a8d16d1388b" />

mserajnik · 1 month ago
This text was generated by Claude Fable 5.1 in Claude Code. A human read it and checked the facts, but did not edit it in any manner. It is written from the reporter's perspective: "I" and "my" refer to the human who posts this comment, not to Claude.

Harness-side details from Claude Code 2.1.257 and 2.1.258 on claude-fable-5-1 (macOS, Anthropic API, interactive TUI), read from the binary and verified against session transcripts. I had opened #91462 for this before I found this thread, and closed it as a duplicate.

Claude Code now renders the absorbed text as a "summarized" line on Fable 5.1. For models that carry the Fable 5.1 capability bundle, interactive first-party sessions send the beta header thinking-display-updates-2026-08-18 with thinking.display: "updates". The API then returns the narration-labelled blocks (the ones @aultra identified) with readable text, and the TUI renders each of them inline, dimmed, with the hint "summarized" (component AssistantNarrationSummaryMessage, gated by isNarrationSummaryBlock). So on Fable 5.1 the absorbed mid-turn text is at least visible as a paraphrase. That paraphrase is written server-side: it contains em dashes and contractions that my output style bans and that the model's own text blocks never contain.

The controls, none of them documented for this purpose:

  • CLAUDE_CODE_THINKING_DISPLAY_UPDATES=false stops the header. It does not stop the absorption. In one session with the variable set, the transcript holds 11 text blocks and 4 narration blocks with empty thinking, so three mid-turn messages were still lost, now with nothing shown at all. This is the pre-2.1.257 behaviour described in this thread. Do not use it as a workaround.
  • --thinking-display omitted (hidden from --help) hides reasoning but leaves the updates mode on for Fable 5.1.
  • showThinkingSummaries: true in settings selects thinking_and_connector_text, which is full thinking summaries plus these updates.

Print mode does not send the header. In four claude -p --output-format stream-json --verbose runs on Fable 5.1, every mid-turn message arrived as a text block, but with the absorption rate reported above that sample is too small to say print mode is immune.

Two things still seem worth a maintainer's attention: a changelog or documentation entry for the "summarized" rendering and its controls, and keeping the original text next to the summary so that --resume and transcript readers do not lose it.

milobird · 1 month ago

Three things that may move this forward.

1. The mechanism this thread inferred is now documented, as intended behaviour. The Thinking docs have a section "Progress updates between tool calls" (platform.claude.com/docs/en/build-with-claude/thinking#progress-updates): on Fable 5.1, Mythos 5.1 and Fable 5 "the model can write a progress update between tool calls … Each one comes back as its own thinking block with its own signature", and "the progress update counts toward usage.output_tokens at its full length, not the summary's". AWS's Bedrock page for the same feature says there is no customer opt-in or opt-out. So this is a serving-layer transformation of Fable's mid-turn text, not a client bug, and it will not reproduce by replaying response shapes through the CLI (which is what the one staff reproduction attempt in this cluster, on #77651, did).

2. Why it is still a bug and not a feature. The model is not told that its mid-turn text is being summarised. Its context records the text as delivered, so when it answers a user question mid-turn (which Fable does, regularly) it believes the user has the answer, the user never receives it, and the original text is billed at full length while being unrecoverable from the stream, the transcript, /export, or Ctrl+O. #89672 shows the downstream effect: the model then denies the loss when the user says they never saw it, sincerely, because from its side nothing is missing. A summariser is only safe for text that really is narration; nothing constrains the model to use mid-turn text that way.

3. First-party measurement, same machine, last two days (Claude Code 2.1.267, macOS). Decoding the signature type token on every thinking block in ~/.claude/projects/, as @aultra described:

  • claude-fable-5-1, mid-turn blocks (after a tool result, before the next tool call): 292 text vs 315 narration. Turn-initial: 255 vs 17. Turn-final: 484 vs 2.
  • claude-opus-5 (7,482 messages) and claude-sonnet-5 (3,877): 0 narration blocks.
  • No message in the corpus contains both a narration block and a text block. The narration block stands in place of the text block, never beside it, which rules out UI collapse of a delivered text block.

What would fix it, from a user's side, is either delivering the original text block alongside or instead of the summary on interactive surfaces, or a model-visible signal that text between tool calls will be summarised so it stops putting answers there. Until then the only complete workaround is running on Opus or Sonnet; no setting changes it, and CLAUDE_CODE_THINKING_DISPLAY_UPDATES=false only hides the summary line.

Related: #89672 (model believes it answered), #65051 (proposed root for the cluster).

DoctorJacoby · 1 month ago

Reproduced, with a worst-case data point: a session where every interleaved-text turn was affected (100%, not intermittent), plus a clean same-day cross-model control.

Environment: Claude Code 2.1.269 (native, Linux/Debian), model claude-fable-5, subscription auth, interactive TUI driven over a PTY. Session 6bcff375-77be-456f-afca-8fe661205b7e, 2026-09-14, ~30 user turns.

Numbers from the session JSONL:

  • 244 assistant records, ~90 tool_use, but only 4 text records in the entire session — the first message of two turns and two turn-final messages. Every mid-turn prose message (long MR-review analyses, multi-paragraph) is absent.
  • 37 messages have the shape [thinking, thinking, tool_use]; the healthy shape [thinking, text, tool_use] occurs 3 times.
  • 111 of 115 thinking blocks are empty with a signature only; the non-empty ones are 127–560 chars.

Shape histogram, if useful for triage:

jq -r 'select(.type=="assistant") | [(.message.id), (.message.content[0].type)] | @tsv' session.jsonl \
  | awk '{ids[$1]=ids[$1]"+"$2} END {for (i in ids) print ids[i]}' | sort | uniq -c | sort -rn

The fingerprint matches this issue exactly: in each affected message the second thinking block is a signed, first-person paraphrase of the missing user-facing text, sitting where the text block belongs. Example — what the model streamed to the client conversation vs. what the JSONL holds:

streamed text: "I'm running as <bot-account> (Developer), which can't merge to protected main — so every merge to main is a click for you. Here's !6: Merge link for !6: <url> — please tick "delete source branch" when merging. Moving on to the stack. Pulling !12."
persisted as thinking: "Since I'm running as <bot-account> I can't merge to protected main, so you'll need to click through !6 (<url>, please tick "delete source branch"). Now moving on to pull !12."

Cross-model control: five claude-opus-5 sessions on the same host, same 2.1.269, same hour — zero occurrences; all persist [thinking, text, tool_use] with full thinking text.

Within-model variance: other claude-fable-5 sessions on this host range from mostly clean (Sep 7) through mostly affected (Sep 10) to the fully-affected session above (Sep 14) — consistent with the intermittency others report, but per-session rather than per-message here.

Possibly relevant timing: this install is enrolled in a server-side experiment (x-cc-atis; assignments under clientDataCacheSlots in ~/.claude.json, atis-latch records in every session JSONL — see #75607). A fresh assignment was cached at 11:54Z on 2026-09-14; the fully-affected session started 12:16Z the same day, while the mostly-clean fable sessions predate the cached assignments. Correlation only — I can't see the cohort semantics — but since the paraphrase blocks are server-signed, a server-side summarizer cohort would explain per-session all-or-nothing behavior.

Practical impact matches #91939: turns ending in AskUserQuestion render as a bare question card with the entire preceding analysis invisible.

(Investigation AI-assisted: evidence gathered and verified with Claude Code on the affected machine.)

alexkay · 22 days ago

I see this issue in the recently released Opus 5.5. Previously it only affected Fable 5 and Fable 5.1, but not Opus 5.0, and it's the reason I stopped using Fable models.

This bug makes experience extremely confusing to the point of making Claude Code nearly unusable.

acelarski · 21 days ago

Opus 5.5 is affected, and the Thinking docs now list it as a progress-update model. This follows up @alexkay's report. The docs' progress-updates section now reads "On Claude Fable 5.1, Claude Mythos 5.1, Claude Opus 5.5, and Claude Fable 5, the model can write a progress update between tool calls." When @milobird quoted it on 2026-09-09, Opus 5.5 was not on that list. The evidence that user-facing text is lost on Opus 5.5 is below. Switching to Opus is no longer a workaround, at least not to 5.5.

Environment (2026-09-23)

  • Model claude-opus-5-5: the message.model of every assistant entry in all four sessions below
  • Claude Code 2.1.280, Windows 11 Pro 10.0.26200, Anthropic subscription
  • Claude Desktop app Claude 2.7032.0 (6c468a) 2026-09-22T05:53:19.000Z, Code tab ("entrypoint":"claude-desktop")
  • VS Code extension anthropic.claude-code-2.1.280-win32-x64
  • Thinking display at defaults: no showThinkingSummaries in user or project settings, and no CLAUDE_CODE_THINKING_* variable in the Desktop app's environment

Reproduction: @UNIVAC-Colonel-Panic's recipe, Desktop app, session 8520ac12-…. The text was lost in 2 of 3 runs. One prompt per run, each with a fresh marker and topic:

In one turn: write one short line saying you are starting, then run ping -n 4 127.0.0.1 > /dev/null; echo one, then write a long formatted markdown explainer (about 1–2 KB: a bold heading, a numbered list of at least six items, inline code) of how git stash differs from a WIP commit, whose first line contains TOPGALLANT-8836, then run echo two, then end with one short line asking me what I saw between the two commands, without repeating the marker.
  • Two lost runs. The explainer (~1.5–2 KB) is stored as a single thinking block whose signature decodes to narration, as @aultra described. The summaries are 296 and 314 characters, there is no text entry, and the marker gets 0 hits. Neither response had a reasoning block before the narration block, so the loss does not need interleaved thinking.
  • One kept run. The third run's explainer was delivered and stored as text. The short opening and closing lines were stored as text in all three runs.
  • What the user saw. The Desktop app rendered the summary as ordinary reply text, with no dimming and no "summarized" hint. Where the explainer should have been, the user saw only "I've laid out the key differences between git stash and a WIP commit — covering where the changes live, visibility, sharing, restoring, branch coupling, and cleanup — with a rule of thumb: …". Nothing on screen says it is a summary, not what the model wrote.

What Claude Code receives. In every session, every reasoning block is stored with an empty thinking field, and every narration block is stored readable. In the docs' display table, that combination is display: "updates", not "summarized". With the display settings at defaults, 2.1.280 therefore appears to send the thinking-display-updates-2026-08-18 beta for Opus 5.5 too, as @mserajnik described for Fable 5.1-bundle models. The client has the summary and writes it to the transcript. The Desktop app then presents it as if it were the reply.

Earlier sessions, from ordinary use:

| session | surface | mid-turn text blocks missing from the transcript | narration blocks | reasoning blocks (all stored empty) |
|---|---|---:|---:|---:|
| 48025d5c-… | VS Code extension | 5 | 5 | 35 |
| 4a1dc633-… | Desktop app | 1 | 1 | 6 |
| d79dc4a1-… | Desktop app (12 short marker blocks, all delivered) | 0 | 0 | 16 |

In 48025d5c-…, three of the missing updates came from one turn. The user confirmed in their next message that they had seen none of them. Their recollection, not certain, is that the VS Code extension showed nothing in their place, unlike the Desktop app's summary styled as reply text. One of those narration blocks:

I'll check the Desktop session's transcript to see if it's missing its hidden block in the same way.

Short markers read Opus 5.5 as unaffected. d79dc4a1-… held 12 one-line marker blocks across 9 turns, some at the turn start and some between tool calls. Six of them followed a procedure like @williamrobotma's, with one marker at the start and one between a tool call and an AskUserQuestion. All 12 were delivered, matching his Opus 5 result. Only 1 of the 12 responses had a reasoning block before its text. A marker test alone will not show the loss on Opus 5.5. The long formatted block above does.

Claude Code's own silence check counts a narration block as nothing shown. Twice in 48025d5c-…, an attachment record {"type":"silent_turn_reminder","text":"The user hasn't heard from you in a while — say in a few words what you're doing, then continue."} was injected after a narration block, with no text block in between.

Sanitized structural excerpts of all four transcripts are available on request.

_Drafted by Claude Opus 5.5 (the affected model) in Claude Code, which also ran the transcript and signature checks. The reporter ran the reproduction turns, reported what was on screen, and reviewed and approved this comment before posting._

ikushum · 17 days ago

Another Opus 5.5 data point, this time through the Agent SDK (@anthropic-ai/claude-agent-sdk 0.3.263 driving Claude Code 2.1.283, macOS, subscription auth). It includes a same-script control on Opus 5 and one setting I haven't seen covered here: turning thinking off does not stop it.

Setup. A folder with one short markdown file describing five cases. One prompt: "Read merge-warning.md. Draft the exact warning sentence for each case, show me all of them in a table, then ask me with the AskUserQuestion tool whether they are the right words." Fresh session per run, settingSources: [], effort high, 6 runs per row. I recorded the first assistant message up to the AskUserQuestion call.

| model | thinking option | table lost | block shape |
|---|---|---|---|
| claude-opus-5-5 | adaptive, display: "summarized" | 6/6 | thinking(772) → thinking(235) → AskUserQuestion |
| claude-opus-5-5 | adaptive, no display | 4/6 | thinking(0) → thinking(219) → AskUserQuestion |
| claude-opus-5-5 | disabled | 6/6 | thinking(0) → thinking(0) → AskUserQuestion |
| claude-opus-5 | adaptive, display: "summarized" | 0/6 | thinking(683) → text(951) → AskUserQuestion |

  • With no display option, the reasoning block comes back empty, but the second block still carries a ~220-character summary of the missing table.
  • With thinking disabled, both blocks are empty. The table is gone and there is nothing left to show, not even the paraphrase.
  • I decoded the signature kind (using @kk1987's script above) on the real session where this first happened. All three lost messages are narration, and every other block in the session is thinking.

Impact. In one real session, three AskUserQuestion prompts in a row were each built on a table or explanation the user never saw. The user answered "where, I don't see" and then "answer me first". The model then said the table "may have been hidden behind the question box", because from its side it had been sent.

For SDK users it is worse than in the TUI. The SDK's thinking.display type only allows 'summarized' | 'omitted', so there's no "updates" option. Under "summarized", a narration block looks exactly like reasoning unless you decode its signature. And no setting returns the original text.

Either of these would fix it:

  1. Deliver user-facing text written before a tool call as a normal text block, at least right before AskUserQuestion, where the question depends on it.
  2. Tell the model that text it writes between tool calls will be summarised, so it puts anything the user must read into the tool input or the final message of the turn.
milobird · 16 days ago

Two data points, from @aultra's signature_label run over my own transcripts:

Opus 5 has been affected since 11 September, though it isn't on the docs' list. Before that date it produced 0 narration blocks (against 712 reasoning and 537 text blocks). From 11 to 19 September (Claude Code 2.1.267–2.1.278) it produced 75, across 12 sessions.

AskUserQuestion often loses the explanation written just before it: 30 of 73 calls on Opus 5.5, and 203 of 441 on Fable 5.1. The system prompt's remedy, restating important text in the final message, can't help here, because the user answers before that message exists.

KamilDev · 9 days ago

Windows data point: same symptom on Opus 5.5.

Environment

  • Claude Code 2.1.289
  • Windows 11, interactive terminal session
  • Model: claude-opus-5-5, subscription auth

What happened

  • I asked a simple question. The model ran several web searches and fetches, wrote a full answer (steps, caveats, source links), then made one more tool call (a file edit) and ended the turn with a one-line "Done: …" message.
  • The one-line final message was the only thing I saw. The full answer never appeared in the UI.
  • It's also missing from the session .jsonl: searching the file for a distinctive phrase from the answer only matches the model's own later searches for it.
  • The model still had the text in its context. It insisted it had answered, and when asked, it repeated the missing message word for word. Only after I asked it to check the .jsonl did it see that the text wasn't there.
  • Same survival pattern as described above: the text block followed by a tool call was lost, and the final text-only message survived.
  • One detail that may help: right before the lost text, the model's context had a harness nudge, "The user hasn't heard from you in a while — say in a few words what you're doing, then continue." The lost text was written immediately after that nudge.

Impact: the turn looks like the model ignored the question, and then the model confidently says it did answer, which is confusing until you know about this bug.

UNIVAC-Colonel-Panic · 9 days ago

Following up on my 25 July comment with a different kind of data point: not a new reproduction, but what the recommended workaround now costs downstream.

The workaround has become an architectural constraint

Because mid-turn text can be absorbed, the only reliable turn shape is: run every tool call first, then emit all substantive text in a single final block. Three months ago that was a Fable 5 precaution. With the Opus 5 and Opus 5.5 reports above, it has to be applied unconditionally -- a session cannot know in advance which model it is on, and Claude Code falls back between them silently.

That rule is now written into my global CLAUDE.md and is load-bearing on every host I run.

Where it breaks something else: any integration whose delivery is itself a tool call

I run Claude Code with the Telegram plugin, so a session can reach my phone while I am away from the terminal. The push to Telegram is an MCP tool call. The workaround requires all tool calls to precede the final text block. Therefore the message to my phone must be composed and sent before the terminal reply exists.

The two outputs cannot be mirrored. They have to be written independently, from intent rather than from the actual terminal text, and they diverge silently.

On 5 October this produced four turns in one evening where a section listing decisions waiting on me reached the terminal and never reached my phone. I found out only by comparing the two screens. Nothing in either channel reports a divergence, because both sends succeeded.

I have since added two hooks of my own to compensate, one of which compares the two at the end of a turn and blocks on a mismatch. It works, but it is a local workaround for a workaround.

Why this may be worth more than one more confirmation

  • It generalizes. Anything that delivers output through a tool call rather than through the final text block inherits the problem: chat channels, notification tools, anything that writes a report somewhere else.
  • It is adjacent to the AskUserQuestion observation above. The documented remedy -- restate important content in the final message -- assumes the final message is the delivery path. Where the delivery path is a tool call, that remedy is unavailable by construction, because the final message has not been written yet.
  • A second reporter hitting this would probably file it as a bug in their own integration and never connect it to this issue.

No new repro to add; the July capture still stands. I am posting this because the blast radius has grown well beyond a missing paragraph.

KamilDev · 8 days ago

Follow-up: still reproduces on Claude Code 2.1.291 (Windows 11, claude-opus-5-5), and I now have a reliable headless repro.

Fingerprint: a lost mid-turn reply is persisted as thinking (empty) → thinking (signed) → tool_use, with no text block. In interactive sessions the second thinking block holds a short paraphrase of the lost reply (197–333 chars in three cases). The model's context still has the full original, but it never reaches the UI or the .jsonl. Text-only final messages survive. Example IDs: msg_011CfkqvPXvtACfohvFTuEuG, msg_011CfkqwPEc1wf5T2wJivZmH, msg_011CfkrTgSnFQkqwxEfgPDm8.

Repro (about a minute per run):

claude -p "<prompt>" --model claude-opus-5-5 --allowedTools "Bash,PowerShell" --output-format json

with a prompt asking for an 8-step read-only system check, one tool call per step, and "before EVERY tool call write me one or two sentences saying what you found so far and what you're checking next". Then count tool-calling assistant messages in the session .jsonl by block layout.

Across 6 runs (48 steps), 17 steps had the double-thinking, no-text layout and 22 had text delivered. The rest had a single thinking and no text, which is ambiguous. Within a run it tends to start partway through: e.g. steps 1–2 delivered, then steps 5–8 all swallowed.

CLAUDE_CODE_THINKING_DISPLAY_UPDATES is not the cause. In 2.1.291 the default interactive request uses thinking.display: "updates" (beta thinking-display-updates-2026-08-18), which is where the paraphrase comes from. But headless runs get empty thinking blocks, so they're not in that mode, and they lose text at the same rate. Setting =1 vs =0 gave 8 vs 9 swallowed steps out of 24 each. The text is dropped server-side whatever display mode is requested. The display mode only decides whether a paraphrase is left behind.

Correction to my earlier comment: the "user hasn't heard from you" nudge isn't required. Most lost replies didn't follow one.

paulmakepeace · 8 days ago

Reproduces on Claude Code 2.1.288 (Claude Desktop, Linux) with claude-opus-5-5.

A reply written just before a Bash tool call was recorded as: an empty thinking block, then a signed thinking block of 229 characters paraphrasing the reply ("Filed the stop-check toil as bug 1087 and finalized the corrected summary..."), then the tool_use, with no text block. My actual wording appears nowhere in the session .jsonl; grepping its distinctive phrase returns 0 hits. Replies in later turns of the same session were recorded normally.

It matters beyond the visuals: a tool of ours reads the last reply before a call (a close report that must carry the operator-facing summary), found only the paraphrase, and had to treat it as "no reply text". It never reposts thinking, so it closed on a separate message field and warned. The operator likely never saw the summary either.