[BUG] Refusal followed by terminal-only AskUserQuestion dialog blocks channel-driven sessions

Status Open
Reported on v2.1.295
Maintainer reply None cached
Activity 0 comments · opened Oct 13, 2026

Summary

In a session driven by a channel plugin (Telegram), a model refusal (stop_reason: refusal) is followed by an AskUserQuestion permission dialog that renders only in the terminal. Nobody can answer it from the channel, so the session blocks and every later channel message queues behind it until the session is restarted externally.

Environment

  • Claude Code 2.1.295, Linux
  • Long-running interactive session under a PTY (systemd user service), bypassPermissions mode
  • Telegram channel plugin; the channel is the only user surface

Observed sequence (happened twice on the same day)

  1. A turn ends with an assistant message whose stop_reason is refusal (transcript JSONL).
  2. About two seconds later the debug log shows executePermissionRequestHooks called for tool: AskUserQuestion.
  3. A terminal dialog appears. The session waits on it indefinitely, and new channel messages are not processed.

The transcripts contain no model-issued tool_use for AskUserQuestion around these events. The dialog therefore appears to be raised by the CLI after the refusal, not by the model.

Expected

A session whose input comes from a channel should never block on a terminal-only dialog. After a refusal the turn should end, and the next inbound message should be handled. If a follow-up question is needed, it should either be routed to the channel or skipped.

Related

The same class of problem also comes from a startup nag ("Make auto mode your default permission mode?"), which opened as a blocking terminal dialog in a fresh interactive session.

Workaround in use

A PermissionRequest hook with matcher AskUserQuestion returns {"decision": {"behavior": "deny", "interrupt": true}} when an env flag marks the session as channel-driven, plus an equivalent PreToolUse deny. In a test session this ends the turn cleanly. It has not yet been confirmed against the refusal path itself.

View original on GitHub ↗