AskUserQuestion: dismissing a card silently discards the typed answer; resolved card replays on mobile

Status Open
Maintainer reply None cached
Activity 3 comments · opened Jul 25, 2026

Environment

Claude Code on the web, mobile app client (remote/cloud session). Observed 2026-07-25.
Note: /bug reports "isn't available in this environment" on this surface, hence filing here.

Bug 1 — dismissing a question card silently discards typed free text

When an AskUserQuestion card is dismissed without a successful submit, whatever the user typed is discarded. The assistant receives only:

The user doesn't want to proceed with this tool use

There is no signal that the user had typed an answer, so it is indistinguishable from a deliberate decline. The assistant then re-asks the same question, turning one lost answer into what feels like a loop. I typed "site, grouped by category" and it never reached the model.

Bug 2 — resolved card keeps re-rendering on mobile

After a question was asked and its result recorded, the card kept reappearing in the mobile app with no new AskUserQuestion call behind it. Only a full app restart cleared it.

Evidence (from the session transcript, UTC)

  • 4 AskUserQuestion calls in the session; 2 returned rejections.
  • The call at 19:28:49 sat 3m16s before returning a rejection - consistent with trying to answer, not declining.
  • The call at 2026-07-22 01:14:32 proves free text IS delivered verbatim when a card submits properly. Only the dismissal path loses it.
  • No AskUserQuestion call exists in the transcript after 19:33:10, yet the card kept appearing until the app was restarted - so the replay is client-side.

Expected

  1. Deliver typed text on dismissal, or at minimum signal "user typed an answer but did not submit", rather than a bare refusal.
  2. Do not re-render a question card whose tool_result has already been recorded.

Impact

Silent loss of user input, plus a re-ask loop that is hard for either side to diagnose. I can supply the session ID privately if useful.

View original on GitHub ↗

3 Comments

mchelen · 1 month ago

Additional detail from the session transcript, plus reproduction steps.

Reproduction

  1. Have the assistant call AskUserQuestion so a question card appears.
  2. While the card is open and unanswered, interrupt the client - background

or force-quit the mobile app, or hit the interrupt/stop control. (Typing
a free-text answer first makes bug 1 visible: that text is lost.)

  1. Reopen the session. The tool call is now recorded as a rejection.
  2. Observe: the card re-appears as an active, interactive card.
  3. Continue the conversation. The card returns on every subsequent

assistant turn.

  1. Restart the app. The card still returns - it is in server-side history.
  2. Only starting a brand-new session escapes it.

Observed over an hour across multiple app restarts. Tapping the card does
nothing; input cannot reach the model, because the tool call already
resolved.

Transcript evidence

Comparing answered vs rejected AskUserQuestion entries:

ANSWERED:
toolUseResult: dict with keys ['answers', 'questions']
is_error: absent

REJECTED / INTERRUPTED:
toolUseResult: string "User rejected tool use"
is_error: true
toolDenialKind: present
(no questions/answers payload retained at all)

Hypothesis: the client renders a resolved card from
toolUseResult.questions/answers. A rejected entry has neither, so it
re-renders as an active card on every history render. That explains why the
replay survives app restarts and recurs on each new assistant turn.

Also: the two cards that replayed worst both carry interruptedByShutdown:
true. Those were NOT user declines - the client was interrupted while the
card was open, and the result was recorded as a generic rejection. That same
event discards the user's typed text, which is bug 1 in this issue.

So both bugs likely share one root cause: an interrupted card collapses to
"rejected" and drops its payload.

Suggested fixes

  1. Preserve the questions/answers payload on rejection so the client can

render a resolved (non-interactive) state.

  1. Distinguish "user declined" from "client interrupted" rather than

collapsing both to "User rejected tool use".

  1. Never render a card as interactive when its tool_use already has a

tool_result of any kind.

alukos · 1 month ago

Cross-surface data point for Bug 1, from the terminal TUI on 2.1.220 (Linux). Same rejection signal, but the typed text does not behave the same way — which suggests the loss you are seeing is surface-specific rather than inherent to the dismissal path.

Details and my two live tests are in https://github.com/anthropics/claude-code/issues/70100#issuecomment-5127672274; the parts relevant here:

1. On the TUI the model gets the same bare refusal. Choosing "Type something" on a single-select question rejects the whole tool call with exactly the string you quote (The user doesn't want to proceed with this tool use). So your point stands on this surface too: the model cannot distinguish "user typed an answer and it didn't make it" from "user deliberately declined".

2. But the typed text is not lost here — it arrives as a separate, subsequent user message. That is the difference from your web/mobile session, where it "never reached the model". Plausibly related to the 2.1.216 changelog entry ("free-text answers now get neutral wording"), which implies the TUI has some delivery path for free text after a rejection. If that mitigation exists on the TUI and not on the web/mobile client, the fix for your Bug 1 may be less "invent a new signal" and more "port the behaviour the TUI already has". Worth checking on the maintainer side.

Note the text still arrives detached from the question even on the TUI, so your Expected #1 ("at minimum signal that the user typed an answer") is unaddressed on both surfaces — the model has no way to bind the answer back to what was asked.

3. A path where free text works in place: multiSelect: true. On the TUI, a question asked with multiSelect: true opens the "Type something" input inside the dialog and returns the typed text inside the tool result, alongside the checked options, with the call intact. Your own evidence points the same way ("free text IS delivered verbatim when a card submits properly. Only the dismissal path loses it").

So the submit path already handles free text correctly; the gap is that single-select routes its free-text exit through rejection instead of through submit. That makes this look less like a missing feature and more like one path never getting the fix the other did in 2.1.181.

Environment: Claude Code 2.1.220 (native install), Linux 6.14, terminal TUI — i.e. a different surface from yours, which is why the delta in point 2 seems worth recording.

JJ213owl · 19 days ago

Additional Android-specific data point (observed 2026-08-11):

  • In the native Android app, a resolved AskUserQuestion card repeatedly reappears after selecting an option and submitting it.
  • The same account, same Claude Code session, same phone, same network works normally in Chrome on that phone; the repeated card does not appear there.
  • Reproduces after force-stopping the Claude app and rebooting the entire device.
  • Reproduces even after clearing all Claude app storage/data, signing in again, and reopening the session.

Because a full local-data reset does not clear the problem, while the same synced session renders correctly in mobile Chrome, this looks less like stale local cache and more like the Android native client reconstructing/rendering an already-resolved AskUserQuestion as pending from synced session history.

This makes the native Android app effectively unusable for the affected session, while the browser remains a working workaround. Happy to provide further reproduction details/session information if useful.