Assistant text emitted before a tool call in the same turn (esp. AskUserQuestion) is intermittently never rendered to the user

Status Closed — duplicate
Reported on v2.1.215
Maintainer reply None cached
Activity 14 comments · opened Jul 20, 2026 · closed Aug 19, 2026

Environment

  • Claude Code CLI 2.1.215, Windows 11 Pro (10.0.26200), PowerShell/Git Bash
  • Occurs with plugin-driven workflows using AskUserQuestion, but the mechanism is generic

Summary

Assistant text that precedes a tool call within the same assistant turn is intermittently not displayed to the user. The most damaging shape: the assistant renders a substantive deliverable (a report/table several KB long) and then calls AskUserQuestion in the same turn — the user sees ONLY the question dialog, with the entire deliverable silently dropped. The user is then asked to choose between options whose context they never saw.

Empirical shape table (accumulated over ~8 occurrences across two weeks)

| Turn shape | Outcome |
|---|---|
| tool calls → text (terminal, no further tool call) | text rendered reliably |
| text → AskUserQuestion (no preceding tool calls) | usually rendered — but we now have one confirmed loss in this shape too |
| tool calls → text → AskUserQuestion | text intermittently lost (most common failure) |
| text → AskUserQuestion that times out / is interrupted | whole turn's text lost |

Repro (as reliable as we've found)

  1. In one assistant turn: call any tool (e.g. a file read or MCP query), then emit ~2-4 KB of markdown (tables/headings), then call AskUserQuestion.
  2. Intermittently, the markdown between the tool result and the AskUserQuestion never appears in the transcript UI — only the question dialog renders.
  3. Same content re-emitted in a turn that ends in plain text (no trailing tool call) renders fine.

Impact

Any workflow that presents a deliverable followed by a decision prompt in one turn (report → options) can silently hide the deliverable. We rewrote our plugin's rules three times assuming an instruction-following defect before isolating it to rendering: only turn-terminal text appears to be display-guaranteed; text between/before tool calls appears to be treated as droppable intermediate narration.

Expected

All assistant text in a turn is rendered in order, regardless of subsequent tool calls in the same turn.

View original on GitHub ↗

11 Comments

gmaldonado-qinetix · 1 month ago

Correction to the shape table from further analysis of the two 2026-07-20 occurrences, based on the user's firsthand account:

The second occurrence was a turn shaped text → single AskUserQuestion with NO preceding tool calls in the turn — previously believed to render reliably. The user saw only the question dialog; the ~2KB of markdown before it never displayed. We initially suspected the user's subsequent interruption of the dialog tore down the turn's text (the timeout-loss shape), but the causality is backwards: the user interrupted the dialog because the text was already missing when the dialog appeared. Text is expected to render before the tool call executes, so a later interruption cannot explain a pre-existing absence.

Net: the loss is not limited to text sandwiched between tool calls. A single trailing AskUserQuestion appears sufficient to drop ALL preceding text of the turn, at least intermittently, even when the text opens the turn. Both 2026-07-20 occurrences involved exactly one AskUserQuestion call — no merged/duplicate question dialogs were involved.

yukihane · 1 month ago

Reproducing on macOS (darwin 25.5.0) with CLI 2.1.217 — so this is not Windows-specific and still present in the latest version. Multiple occurrences over two days, all in plan mode, with both text → AskUserQuestion and tool calls → text → AskUserQuestion shapes. Model: claude-fable-5.

Two findings that may help narrow the bug surface:

  1. The lost text is fully persisted in the session .jsonl. I grepped distinctive phrases from two dropped messages and both were present in ~/.claude/projects/<project>/<session-id>.jsonl. So the loss happens purely in the display layer — both the live TUI and the transcript view (ctrl+o) skip the text, but persistence is intact. Recovery workaround:

``bash
jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="text") | .text' <session>.jsonl | tail -50
``

  1. Model correlation (anecdotal): this never occurred for me on Opus 4.x and started immediately after switching to claude-fable-5. The bug itself is clearly in the TUI, but Fable emits interleaved text before tool calls (especially explanation → AskUserQuestion in plan mode) far more often than Opus did, so the triggering turn shape became much more frequent. This may explain why reports of this are recent.
devan-borsboom · 1 month ago

Controlled A/B data confirming the model correlation suggested above, with transcript-level checks.

Environment: Claude Code CLI 2.1.220, macOS (darwin 25.5.0), iTerm2, interactive session (not plan mode). Models compared: claude-fable-5, Sonnet 5, Opus 5.

Method: blind probe protocol run in fresh sessions per model. Each probe reply = plain text, then an AskUserQuestion in the same turn, with the tools-before-text variable controlled (none / one Read / one Bash). Short class = 130-240 chars; long class = ~900-1100 chars. The user scored visibility live via the question box itself; the session then greped its own .jsonl for each probe marker.

Results:

| Model | Class | Probes | Visible to user | Marker present in session .jsonl |
|---|---|---|---|---|
| Sonnet 5 | short | 3 (none/read/bash) | 3/3 | 3/3 |
| Sonnet 5 | long | 3 | 3/3 | 3/3 |
| Opus 5 | short | 3 | 3/3 | 3/3 |
| Opus 5 | long | 3 | 3/3 | 3/3 |
| Fable 5 | short | 3 | 0/3 | 0/3 (not recorded at all) |
| Fable 5 | long | 3 | 0/3 | 3/3 (recorded, never rendered) |

An earlier 20-probe run on Sonnet 5 (10 short / 10 long, same text→AskUserQuestion shape) was also 20/20 visible and 20/20 recorded.

Notes that may help triage:

  1. Both variants reported in this thread reproduce, and they split by length on Fable: long text was persisted to the JSONL but never rendered; short text never reached the JSONL at all.
  2. In a long-running production Fable session the same day, ~13 substantive messages (400-1000+ chars, various turn shapes: with and without preceding tool calls, ending in AskUserQuestion) were lost and absent from the JSONL, while ~20 short status lines (<260 chars) followed by NON-AskUserQuestion tool calls all rendered normally. One exception observed: a single ~660-char text → AskUserQuestion reply did render on Fable, so it is intermittent there, but the failure rate in the text→AskUserQuestion shape was ~13/14 for us on Fable vs 0/26 across Sonnet/Opus.
  3. The tools-before-text variable made no difference in any model (contrary to our initial hypothesis).

Happy to share the probe prompt files if useful for a regression test.

DevenDucommun · 1 month ago

Another occurrence, this time on 2.1.220 (latest as of today), macOS 15 (Darwin 24.6.0), kitty terminal.

The shape was the second row of your table: a text-only explanation of roughly 1.5 KB followed directly by AskUserQuestion in the same turn, with no earlier tool calls in that turn. The entire text block never rendered. The user's next message was literally "what lesson? i don't see it". So that row is now a confirmed full loss on a second platform and on the current release.

Some history that may help triage: #30422 (last line truncated before the widget) was closed completed in March 2026, and #65841 (prompts never rendering) was closed not planned in July. This issue looks like the surviving superset of both.

Workaround we now run, in case it helps others: a PreToolUse hook on AskUserQuestion that parses the session transcript jsonl, measures the contiguous assistant text since the last tool event, and blocks the call once per turn when that segment exceeds a threshold (~350 chars). The block message tells the model to either end the turn with the content and ask in the next turn, or write the content to a file first. The retry is allowed so it cannot loop. Since the loss is render-only, dropped text is also always recoverable from the transcript jsonl or /export.

Fix direction, from the outside: the behavior is consistent with only turn-terminal text being display-guaranteed. Either flushing pending assistant text blocks to scrollback before mounting the interactive widget, or re-rendering the preceding blocks when the widget resolves, would close this.

Disclosure: this comment was drafted with AI assistance inside a Claude Code session; the occurrence described above was observed directly by the human user, and the hook workaround was verified end to end before posting.

ForrestGrump · 28 days ago

Another reproduction, adding a platform not yet represented in this thread: Linux under WSL2.

Environment

  • Claude Code CLI 2.1.220 (current)
  • Model: claude-fable-5
  • Linux on WSL2, kernel 6.18.33.2-microsoft-standard-WSL2, bash
  • Interactive terminal session (not plan mode)

Occurrence (2026-08-02)
Turn shape was the text → AskUserQuestion row: a multi-paragraph explanation followed by an AskUserQuestion call in the same turn. Only the question dialog rendered; the explanation never appeared. Confirmed by comparing the session transcript against a screenshot of what the user actually saw — the text was authored, and was not displayed. Consistent with the render-only diagnosis in the comments above.

Two data points that may help triage

  1. Platform. Combined with the existing Windows 11 and macOS (iTerm2, kitty) reports, this now reproduces on WSL2 as well, on 2.1.220. Nothing platform-specific is left to explain it.
  2. Not limited to AskUserQuestion. The user reports numerous occurrences over time, and recalls the same swallowed-text behavior with other tools following the text in the same turn, not only AskUserQuestion. Flagging this as a scope note rather than a measured claim: unlike the 2026-08-02 case above, those earlier occurrences were not verified against the transcript at the time, so I cannot rule out that they were all AskUserQuestion. If the fix targets only the interactive-widget mount path, it may be worth checking whether the general "text before any tool call" path drops text too.

Model correlation matches the A/B results already posted: not observed with Opus models in this same CLI version and terminal. Sonnet and Haiku were not tested here.

Impact, restated from the user's side: the practical harm is that a question dialog arrives with none of the reasoning the model wrote for it. The user answers without the context, and reasonably concludes the model gave no explanation at all — which also misleads them about the model's behavior, not just the UI's.

dhscfh · 28 days ago

Confirming reproduction on macOS — this is not Windows-specific.

Environment

  • Claude Code CLI 2.1.220, macOS 26.6, iTerm2/zsh

Observed

Same shape as the OP's most common failure: tool calls → ~2-3 KB markdown (headings + tables) → AskUserQuestion in a single assistant turn. The markdown between the last tool result and the question dialog was truncated to a single line fragment immediately above the dialog — the rest was never rendered. The user was prompted to approve a design they had never been shown.

Hit this twice in one session (both times the turn contained tool calls before the text). Re-emitting the identical content in a turn that ends in plain text (no trailing tool call) rendered it in full, matching the OP's observation that only turn-terminal text appears display-guaranteed.

One additional detail that may help triage: in our case the swallowed text was not fully invisible — its first line rendered as a truncated fragment directly above the AskUserQuestion dialog, suggesting the renderer began emitting the text block and was cut off by the dialog paint rather than the block being dropped before rendering.

Suggest removing/expanding the platform:windows label — this reproduces on macOS with the same turn shapes.

nircoh-onyx · 27 days ago

Block-level evidence for the "not recorded at all" bucket in the A/B table above: in our sessions the lost text arrives from the API as signature-bearing thinking blocks, not as text blocks. It is not purely a display-layer drop.

Environment: CLI 2.1.220, macOS (darwin 25.5.0), claude-fable-5 (high reasoning effort), interactive sessions inside a PTY we can capture out-of-band.

What we found

  1. Extra signed thinking block in the text's exact position. In an affected session, every assistant message where the model authored mid-turn text (text followed by tool_use in the same message) is persisted as thinking, thinking, tool_use — one thinking block more than usual — with the extra block carrying a genuine API signature. Messages with no authored mid-turn text never have the extra block. Perfect correlation across dozens of messages. Since the CLI persists thinking blocks with empty thinking content (signature only), the text is unrecoverable from the JSONL — which would read as "not recorded at all" if you grep for the marker, when it is actually recorded as an empty-content thinking block.
  1. PTY-stream proof it never renders. We ran marker probes: save a byte cursor on the session's PTY, author a mid-turn text block containing a distinctive marker, then read the PTY from the saved cursor seconds later (window verified untruncated — spinner repaint frames from the same interval are present). The marker never appears in the terminal byte stream. So in this failure mode the text is not occluded or cleared by a redraw; it is never written to the terminal at all, consistent with the client receiving it as thinking.
  1. It latches per session. The affected session rendered and persisted every mid-turn text normally for ~30 minutes, then flipped at a precise timestamp; from the next API request onward, every mid-turn text converted (including plain status lines before Bash calls, not just AskUserQuestion shapes), and the latch survived an overnight gap and new user turns. In our case the flip coincided to the second with an async background-task notification being queue-injected mid-turn (a queue-operation entry in the JSONL). n=1 on that trigger, but a second affected session flipped with no queue injection, so injection is at most one of several triggers. #80136 reports onset after a mid-session /model switch — also a mid-conversation context perturbation.
  1. The concrete AskUserQuestion case matches. A separate session's "deliverable + AskUserQuestion" loss shows the same signature: the message is persisted as thinking, thinking, tool_use(AskUserQuestion) with ~1KB of output tokens and no text block — yet the model quoted the "lost" deliverable verbatim in a later turn, so the content remained in its live context.

Implication for triage

There appear to be two distinct mechanisms behind identical user-facing symptoms, and the thread already contains evidence of both:

  • Render-only drop: text block present in the JSONL, never displayed (yukihane's finding; long-class probes in the A/B table).
  • Thinking conversion (this comment): the would-be text reaches the client as a signed thinking block — invisible by design, persisted with empty content, still in model context. Given the signatures are valid, the conversion happens upstream of the client (model or API streaming layer), which fits this bug reproducing across CLI, desktop app, and VS Code, and fits the strong fable-5 correlation in this thread.

Happy to provide sanitized JSONL excerpts (block structure, signatures lengths, timestamps) if useful.

ForrestGrump · 27 days ago

Following up on my earlier WSL2 report, where I flagged as an unverified recollection that this is not limited to AskUserQuestion. I can now upgrade that to a measured claim: today it reproduced with a plain Edit tool call, verified against the session transcript, in a session where the trailing tool was never AskUserQuestion.

Environment

  • Claude Code CLI 2.1.220
  • Model: claude-fable-5
  • Linux under WSL2, kernel 6.18.33.2-microsoft-standard-WSL2, bash, interactive session (not plan mode)
  • 2026-08-03

The occurrence

Turn shape: prior tool calls → multi-paragraph analysis the user had explicitly asked for (~2 paragraphs plus a recommendation) → Edit call on a markdown file, all in one assistant message.

What the terminal rendered: the previous turn's text, the tool-use summary line ("Searched for 1 pattern, listed 1 directory, ran 1 shell command"), the Edit diff block, and the next assistant message. The analysis between them never appeared.

The user's next message was: "did you reply something after that part? Did you not reply anything or is it the tool-call-swallows-output bug?" — i.e. from the user's seat, "the model said nothing" and "the renderer dropped it" are indistinguishable.

Transcript evidence: matches the thinking-conversion mechanism, with Edit

This is the block structure @nircoh-onyx described, so I can corroborate that mechanism on a non-AskUserQuestion tool. Comparing the failing message with a control from the same session, same model, same trailing tool type, ~11 minutes later:

| | Failing message msg_011CdfkFHpkXL7rJNzVfXpcW (11:36:41Z) | Control msg_011Cdfm5uLXHiG6cVSJ8MrQq (11:47:36Z) |
|---|---|---|
| Block sequence | thinking, thinking, tool_use:Edit | thinking, text(197), tool_use:Edit, tool_use:Bash |
| Signature lengths | 4912, 2696 | 5720 |
| text block | absent | present |
| Rendered to user | no | yes |
| output_tokens | 2690 | 2063 |

An extra signed thinking block sits in the exact slot the text block occupies in the control. Both thinking blocks persist with empty content, so the authored text is unrecoverable from the JSONL — a grep for it returns nothing, which reads as "never sent" rather than "dropped". Consistent with the "not recorded at all" bucket in the A/B table above, but here with a length class (multi-paragraph) that the earlier table put in the render-only bucket, and with an ordinary editing tool rather than an interactive widget.

Two findings that may narrow triage

1. It did not latch in this session. @nircoh-onyx reported the conversion latching per session from a precise timestamp onward. Mine did not. Over a 90-minute session I get 22 messages shaped thinking, thinking, …, tool_use (no text block) interleaved with 25 shaped thinking, text, …, tool_use (text present and rendered), alternating throughout — e.g. 11:35:54 fine, 11:36:41 lost, 11:36:55 fine. So per-message intermittency and per-session latching are both real; a fix keyed only to a latch/trigger event would miss this.

Caveat on that count: only the 11:36:41 message is independently corroborated as having carried user-facing text (user reported not seeing it; model reported writing it). Some of the other 21 may be genuine two-segment reasoning. I offer the ratio as a shape census, not as 22 confirmed losses.

2. The conversion only occurred mid-message. In this session, zero messages ended with thinking, thinking and no tool call — every double-thinking message had a tool_use after it, and all 12 turn-terminal thinking, text messages rendered. That is more specific than "trailing AskUserQuestion triggers it": the affected slot is text followed by any tool_use in the same message. In this session the trailing tool was Bash, Read, Write, Edit, ToolSearch, and once AskUserQuestion — the widget is not required.

Why this is worse than the AskUserQuestion case

With AskUserQuestion the user at least knows a turn happened and can ask what it was about; the dialog is a visible anchor. With an ordinary tool call there is no anchor at all:

  • The model believes it delivered analysis the user requested. In the conversion mode the content stays in the model's live context, so it proceeds as if the user has it.
  • The user never saw it, and cannot tell "the model chose not to explain" from "the UI ate the explanation".
  • The user then makes decisions on missing context while the model assumes shared context. In my case the swallowed block was a code-verified finding plus a recommendation the user had explicitly asked for, immediately ahead of a decision.
  • Neither side receives any signal that content was dropped. There is no truncation marker, no error, and in this failure mode no transcript record to recover from.

That last point is the ask: even absent a full fix, a client-side signal — e.g. surfacing "this message contained N thinking blocks and no text" or a marker when a signed thinking block carries empty content in the text position — would let both the user and the model detect the loss instead of silently diverging.

Disclosure: drafted with AI assistance inside a Claude Code session, at the request of the human user who experienced the occurrence. The transcript block structure, signature lengths, and shape census above were read directly from the session JSONL; the rendering failure was observed by the human user. Message content is withheld as it is from a private project.

Ennvoy · 24 days ago

Same issue here — adding a data point.

Environment: Claude Code CLI 2.1.223, Windows 11 Pro (10.0.26200).

  • Shape matches the table above: tool calls → text → AskUserQuestion in the same turn loses the preceding text almost every time in our sessions (content is Traditional Chinese markdown, typically 1–4 KB with headings/tables).
  • The user only sees the question dialog and has to answer options whose context was never displayed.
  • Severity signal: this is consistent enough that we keep a standing user-level instruction telling the model to (a) duplicate all background/trade-offs into the AskUserQuestion question text and option descriptions, and (b) deliver the full explanation as a separate file — i.e. we treat the popup as required-to-be-self-contained because prose in the same turn cannot be trusted to render.

Happy to provide session JSONL excerpts if useful.

namidaka · 23 days ago

Same issue here , it's been there for a long time

alasano · 22 days ago

This is by far the craziest bug open in Claude Code today. I experience it daily.

User requirement: I type a message to Claude, when Claude responds I see that message 100% of the time

Seems pretty simple but this has been ongoing for ~1.5 months or more.

#67071 #65662 and a bunch of other issues relate to this.

Showing cached comments. Read the full discussion on GitHub ↗