[Bug] Background (daemon) sessions drop assistant text blocks from transcript when response mixes text with tool_use (regression 2.1.160 → 2.1.161)
Environment
- Claude Code: 2.1.161 (npm install, Linux)
- OS: Ubuntu 24.04 (kernel 6.17)
- Session type: background job, daemon backend (
"backend": "daemon",sessionKind: "bg"in the transcript records) - Model: claude-opus-4-8
Summary
In background (daemon) sessions, assistant text blocks are not persisted to the session transcript (~/.claude/projects/<project>/<session>.jsonl) whenever the response also contains tool_use blocks and two thinking blocks (interleaved thinking). The transcript ends up with only thinking records (empty thinking: "", signature present) plus the tool_use records — the text record between them is missing entirely.
This is a regression from 2.1.160: the same session has turns from the previous day on 2.1.160 where every text block was persisted correctly. After the daemon updated to 2.1.161 and the job restarted, only the very first response of the run (which had a single thinking block) kept its text; every subsequent response lost its text block.
Observed transcript pattern (sanitized)
# first response after restart — text persisted (single thinking block)
record 93 assistant thinking (thinking:"", signature present) req_A
record 94 assistant text[107 chars] req_A
record 95 assistant tool_use: ToolSearch req_A
# every later response — text block missing
record 99 assistant thinking (thinking:"", signature present) req_B
record 100 assistant thinking (thinking:"", signature present) req_B
record 101 assistant tool_use: Agent req_B
record 102 assistant tool_use: Agent req_B
# the response's text block was streamed live but never written
record 123 assistant thinking (thinking:"", signature present) req_C
record 124 assistant thinking (thinking:"", signature present) req_C
record 125 assistant tool_use: AskUserQuestion req_C
# a ~150-word answer preceding AskUserQuestion is absent from the jsonl
Scanning the whole file: after the restart on 2.1.161 there are zero assistant text records other than the first response, across ~10 consecutive responses that all contained user-facing text. Text-only final responses (no tool_use) DO persist fine.
Impact
- The background job viewer replays the conversation from the jsonl, so the user sees only tool-call summaries and a bare AskUserQuestion dialog with none of the assistant's prose (including the main deliverable the job was asked to produce).
- The job state extractor / timeline gets
text: ""for the turn, so the job list shows a stale state and detail (timeline.jsonlentry recorded with empty text). - The lost text is unrecoverable from disk — it only exists in the daemon's memory until the session produces a final text-only response.
Steps to reproduce
- Install Claude Code 2.1.161 on Linux, daemon backend.
- Start a background job that runs multiple turns mixing assistant prose with tool calls (extended/interleaved thinking active, so responses contain 2 thinking blocks).
- Inspect
~/.claude/projects/<project>/<session>.jsonl: responses withthinking ×2 + tool_usehave notextrecord; reopening the job in the viewer shows no assistant prose.
Expected behavior
Assistant text blocks are persisted to the transcript for every response, as in 2.1.160. (Thinking blocks being persisted with empty content + signature looks intentional; the regression is specifically the dropped text blocks.)
14 Comments
Confirming this regression on macOS in a regular interactive TUI session — it is not specific to Linux or the daemon backend, and it is still present in 2.1.162.
Environment
~/.local/share/claude/versions/), macOS (Darwin 25.5.0)backend/sessionKindfields in the transcript records)Observed (transcript census of one ~5h session)
.jsonl: 67thinking, 79tool_use, only 11text.Version timeline corroboration
claudesymlink to 2.1.162; every session started after that exhibits the bug, across different projects — so it reproduces consistently on 2.1.162 interactive sessions, not just 2.1.161 background jobs.Workaround we're using: relaunching panes with the cached previous binary (
~/.local/share/claude/versions/2.1.160 --resume <session-id>).Also reproducible in interactive (non-daemon) sessions, on macOS, in 2.1.163, so it's broader than the daemon backend.
Environment: Claude Code 2.1.163, macOS 15 (Darwin 24.6.0), Terminal.app, Anthropic API, model
claude-opus-4-8[1m].Identical fingerprint: an assistant response of shape
thinking → text → thinking → text → tool_use(the tool_use was a Bash call withrun_in_background: true) was persisted to the session jsonl as:{"type": "thinking", "thinking": "", "signature": "CAESzAUK..."}
{"type": "thinking", "thinking": "", "signature": "CAESzQgK..."}
{"type": "tool_use", "name": "Bash", "input": {"command": "...", "run_in_background": true}}
Both text blocks missing; grep for distinctive phrases across the whole
~/.claude/projects/<project>/dir: 0 hits. Responses in the same session with a single thinking block kept their text, matching the pattern from above.Two more impacts:
Cross-reference: same regression analysed on #65620 (interleaved-thinking pattern, version census, date-onset data); also the original report on #64129. Linking here so the relation is visible if/when triage consolidates.
We're hitting what looks like exactly this bug, and we have some additional evidence that may help narrow it down — including one occurrence where the text block was absent from all three surfaces (session
.jsonl,assistantstream events, and even thecontent_block_deltapartials).Environment
claude -p --output-format stream-json --include-partial-messages --verbose(reproduces in both one-shot--resumeand long-lived--input-format stream-jsonmodes)--mcp-configFingerprint
When an assistant message combines interleaved thinking + text + tool_use in the same message, the CLI sometimes drops the text block:
.jsonl— the message appears only asthinking+tool_uselines sharing the samemessage.id.assistantstream-json event either (confirmed 2026-07-04).text_deltapartial events — so it renders live and then vanishes when a client reconciles with the.jsonl.Nondeterministic: messages with the same shape sometimes persist fine.
Evidence across ~8 lost messages (2026-07-03/04)
[thinking, thinking, tool_use(mcp tool)]— long answers (~2–3 KB of markdown each) gone.[thinking, text→dropped, tool_use(Read)]with a built-in tool, so it is not MCP-specific.assistantstream events into a sidecar store: for the lost messages the sidecar has no entry at all, while short text messages in the same turns were captured normally → the text block was absent from theassistantevents too, not just from persistence.text_delta-accumulation fallback, the bug hit again and the fallback captured nothing for the lostmessage.id(while capturing deltas for neighboring messages of the same turn). In that case the text was absent from.jsonl,assistantevents and deltas — the user never saw the reply at all.[thinking, text, tool_use(Read)]shapes), while other turns in the same session persist identical shapes fine. That worst turn was the first--resumeturn after our host app restarted, in case that helps.Impact beyond display
Since the
.jsonlis the source of truth for--resume, the model itself permanently loses that part of its own context on resume. Summaries, handoffs and any tooling reading the transcript also miss it.Workaround we ship (partial)
We accumulate
text_deltaevents permessage.idinto a sidecar and re-inject the text on load when the.jsonlmessage hastool_usebut no text block. That recovers display in most cases — but not the all-three-surfaces occurrences, and the model context on resume is still missing the text.Happy to provide the raw
.jsonllines / stream-json captures for the affectedmessage.ids if useful.Raw-stream proof: the text block never reaches the CLI's stdout — it is replaced by an extra signed-but-empty
thinkingblock (server-side, not a client parsing bug)Following up on my earlier comment: I instrumented a tap that records every raw stdout line of
claude.exebefore any client-side parsing. Setup: CLI 2.1.196, Windows 11, modelclaude-fable-5, headless--output-format stream-json --include-partial-messages --verbose, long-lived process via--input-format stream-json, MCP stdio tool (vox_ask).Block structure of the assistant messages in one session (content redacted — only block types and streamed char counts;
sig=signature_deltachars on a thinking block that streamed zerothinking_deltachars):Findings:
textblock never exists in the CLI's stdout for the broken messages — nocontent_block_startof typetext, zerotext_deltas. The transcript.jsonlfaithfully records what the stream delivered, so this cannot be recovered or fixed client-side.thinkingblock that streams 0 thinking chars and only asignature_delta— the user-visible answer appears to be repackaged as an encrypted/signed thinking block. Consistent with #65620.tool_use(interleaved thinking on) lost the text 6 out of 6 times, while text preceding built-in tools (PowerShell/Grep/Read) streamed fine 6/6. With--input-format stream-json(persistent process) it reproduces every time; in one-shot-pmode it is intermittent.Happy to share the full (redacted) raw ndjson tap if useful.
Confirming this is still present on 2.1.212 (current
latest/next;stable2.1.205 also affected — the 2.1.205–2.1.212 changelog claims no related fix) — Linux (WSL2 Ubuntu), interactive TUI session, Anthropic API, modelclaude-fable-5. Same fingerprint as the OP and the #65620 shape table: any assistant API message persisted with ≥2 thinking blocks has zerotextrecords, while single-thinking messages from the same session persist text normally.Three data points the thread doesn't have yet:
1. Corpus scale — zero counterexamples. Sweep of 26 recent session transcripts on one machine: 477 assistant messages with ≥2 thinking blocks, none with a persisted text block (all fable-5). One live session in detail, re-run at the time of this comment (grouping key is the API
message.idshared across the JSONL lines):(Fittingly, the session that authored this comment reproduced it too: 9 multi-thinking messages at the time of posting, zero persisted text blocks.)
2. The dropped text is billed.
usage.output_tokenson the textless messages is consistent with substantial text having been generated. Two incident messages that persisted onlythinking ×2 (empty, signature present) + one small tool_usebilled 4767 and 3278 output tokens respectively; a comparable single-thinking control from the same session (thinking + 78-char text + tool_use, text persisted fine) billed 1162. The token accounting says the prose existed; the store says it never did.3. On 2.1.212 the loss is at (or before) the client — the text never renders in the TUI either. Reproduced textless multi-thinking messages ahead of three different tool types (
Bash,Skill,AskUserQuestion), so it is not widget-specific. In our incident turns the prose was absent from the live viewport at incident time as well as from the JSONL — matching the raw-stream tap finding above (text block never reaches the CLI's stdout) rather than the earlier "rendered on screen but not persisted" reports from 2.1.162–2.1.165. The worst-case shape isthinking ×2 + AskUserQuestion: the dialog's own question/option text renders completely, but the reasoning laid out for the decision is gone, so the user answers the gate blind.The fingerprint is checkable in any interleaved-thinking transcript with the jq above; happy to run further forensics on request.
@bogini Is there any update on this? It's quite a severe issue — users are asked to approve content they never saw, deliverables are silently lost, and in several variants the text is missing from the session transcript entirely, so the loss is unrecoverable.
It also seems to be one of the most-duplicated open bugs right now: we've identified 31 duplicate reports of this cluster so far (20 of them still open, spanning the CLI TUI, the VS Code extension, and the Desktop app — see the cross-references above), with new ones still being filed weekly.
_Drafted by Claude (Anthropic AI assistant)._
From a simple user experience perspective, I don't understand how anyone uses Fable for more than a day and doesn't notice that the model regularly believes it has said things to the user that the user never sees.
It's an issue that interrupts every single session I have with Fable, every day, multiple times a day I experience this. I ask Fable about something, Fable shows some tool calls and perhaps some text but seems to completely ignore my question (from my perspective), so I tell Fable that it didn't reply. It says it did. I show Fable a screenshot of what it actually did from the user side. Fable says that the reply it intended never made it to me, but it is absolutely convinced that it sent it.
It's an astonishing bug to be ongoing like this.
Pretty much exactly my feelings, as expressed in another of these threads.
This is the worst bug in Claude Code _by far_.
And to anyone who doesn't agree, how is "_The model says something and the user doesn't see it_" not an absolute fundamental product breaking severity 1 bug?
Like @vbiroshak, every single day, multiple times per day, I realize I'm missing a huge chunk of information and have to ask the model to repeat what was missing.
It's okay though because it's only the most expensive model Anthropic offers
This is STILL happening @bcherny! I just gave feedback on a plan and it produced no response, just re-presented the plan.
Fable has been out for nearly 3 months and this has been a constant, persistent issue, and I find it baffling that nobody at Anthropic seems to notice? How is this possible? Something fundamentally is broken inside the organisation that enables something like this to continue for so long. You're supposed to be a $1TN company?
Feedback reference ID 1fd499cc-eaf9-457b-9f34-4f1b90ac4163
Also running into this bug almost daily. Very frustrating and causes a lot of confusion and work to be lost. Happens to me on Fable and Opus 5. Seems to be a harness problem? My /feedback feature already has a few drafts racked up about this bug.
I often see confusing AskUserQuestion dialogs asking me about things out of the blue without any context and think I'm missing something, then realize, "Ah, it's that bug again".
Or it's in the middle of some task and I'll queue up a quick question. When my question posts, it'll think, then just continue on with what it was doing - seemingly ignoring me - but it thinks it answered me.
Claude Code: 2.1.251 (Arch Linux x64 7.1.8)
https://github.com/anthropics/claude-code/issues/65620#issuecomment-5652484152
As I said there:
This shit still hasn't been fixed, after ages.
Makes a tool-driven workflow on Fable models completely useless.
Still present on 2.1.280 (latest) with Opus 5.5 via AWS Bedrock: interactive TUI, tmux, Linux. So it's not limited to Fable, the first-party API, or the IDE extensions.
Same fingerprint from one session's .jsonl: all 11 assistant messages with 2 or more thinking blocks + tool_use have no text record. Every 1-thinking message kept its text. Five of those 11 were confirmed as text the user never saw (4 before AskUserQuestion, 1 before Skill). Markdown formatting and preceding tool calls made no difference in controlled tests.
Still reproducing on Claude Code 2.1.284, desktop app (Code tab), macOS 26, model claude-opus-5-5. That contradicts #84907's observation that Opus is unaffected. In one session, all 5 mid-turn messages the user never saw are responses recorded as
thinking(index 0) +thinking(index 1, empty text, 1-3 KB signature) +tool_use, with notextrecord. Every displayed message has the shapethinking+text+tool_use, or is the turn's final message. The dropped text often came right before anAskUserQuestion, so the user answered without the context the question depended on.