[BUG] Assistant text in the same response as an AskUserQuestion tool_use is never persisted to the session JSONL (silent data loss)
Summary
When an assistant response contains both text content and an AskUserQuestion tool_use block, the text is never persisted to the session JSONL file. This causes:
- Invisible content: the text never displays in the terminal UI
- Invisible in transcript: the text does not appear in
ctrl+o(transcript view), which renders from the JSONL - Permanent data loss: the text is absent from
~/.claude/projects/<project>/<session-id>.jsonl— the assistant message'scontentarray contains only thetool_useblock, with the text block structurally missing (not truncated, not marked — simply absent) - Uninformed consent: users answer approval dialogs without ever seeing the content they are approving (drafted plans, summaries, diffs)
Environment
- Claude Code version: 2.1.209
- Platform: macOS (darwin)
- Observed repeatedly: first 2026-06-10, recurrences 2026-06-11, 2026-07-13, 2026-07-14 (multiple sessions; example affected session ID prefix:
704d9ae7)
Minimal repro
- Start a Claude Code session.
- Get the assistant to emit a non-trivial text block (a summary, plan, or draft) and an
AskUserQuestiontool call in the same response. - Answer the dialog, then inspect the session JSONL (
tailthe file under~/.claude/projects/<project>/). - The last assistant entry's
contentarray contains only thetool_useblock — the text block is absent.ctrl+oshows no trace of the text either.
Expected behavior
All content blocks of an assistant message (text + tool_use) are persisted to the session JSONL, so the transcript view can display them and --resume reloads the full context. Whether the TUI renders text behind the dialog is a separate (lesser) rendering question — persistence should be unconditional.
Actual behavior
The text block is dropped from the persisted message. Observed JSONL entry shape:
{"type":"assistant","message":{"content":[{"type":"tool_use","name":"AskUserQuestion","...":"..."}]}}
For comparison, text followed by other tool calls (e.g. Bash) in the same response renders on screen and appears in the transcript as expected in our sessions — the loss is observed specifically with AskUserQuestion turns.
Impact
- Users approve significant content (plans, diffs, briefs) they never saw — the dialog's question text is often "approve this?" while the "this" was in the dropped text block.
- Sessions cannot be faithfully reconstructed from the JSONL;
--resumeloses the dropped context permanently. - Anything relying on the JSONL as a record (audit, tooling built on transcripts) silently misses content.
Workaround we deployed (harness-side)
A PreToolUse/PostToolUse hook pair on AskUserQuestion:
- PreToolUse denies the dialog when same-turn assistant text exceeds a threshold, forcing the model to end the turn with the content and ask in the next turn.
- PostToolUse injects a deterministic reminder that any same-turn text was never displayed, prompting the model to re-present it.
This works but is a band-aid — the persistence bug should be fixed at the serialization layer.
Questions for investigation
- Is the text block dropped at JSONL-serialization time, or never collected from the streaming response?
- Is this specific to
AskUserQuestion, or a wider text-before-tool_use issue? (#24691 describes streaming text disappearing before tool calls generally and may share a root cause — but it is framed as a UI/streaming issue; this report's distinct finding is that the text is structurally absent from the persisted JSONL.)
Related issues
- #24691 — Streaming text disappears entirely when followed by tool calls in same response (possibly same root cause; broader scope; UI-framed)
- #23862, #30422 — AskUserQuestion widget obscures/truncates preceding text (UI layering — distinct from persistence loss)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗