[BUG] Assistant text in the same response as an AskUserQuestion tool_use is never persisted to the session JSONL (silent data loss)

Open 💬 1 comment Opened Jul 14, 2026 by cyphernext

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:

  1. Invisible content: the text never displays in the terminal UI
  2. Invisible in transcript: the text does not appear in ctrl+o (transcript view), which renders from the JSONL
  3. Permanent data loss: the text is absent from ~/.claude/projects/<project>/<session-id>.jsonl — the assistant message's content array contains only the tool_use block, with the text block structurally missing (not truncated, not marked — simply absent)
  4. 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

  1. Start a Claude Code session.
  2. Get the assistant to emit a non-trivial text block (a summary, plan, or draft) and an AskUserQuestion tool call in the same response.
  3. Answer the dialog, then inspect the session JSONL (tail the file under ~/.claude/projects/<project>/).
  4. The last assistant entry's content array contains only the tool_use block — the text block is absent. ctrl+o shows 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; --resume loses 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

  1. Is the text block dropped at JSONL-serialization time, or never collected from the streaming response?
  2. 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)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗