Spurious mid-run interrupt: lone ESC from terminal report sequences misread as interrupt keypress during agent-status re-render (unattended tmux sessions)

Status Open
Maintainer reply None cached
Activity 1 comment · opened Aug 15, 2026

Symptom

An unattended, autonomous Claude Code session — no operator attached, no operator input sent — halts mid-tool-call with the TUI showing Interrupted · What should Claude do instead? and a tool result of [Request interrupted by user for tool use] (is_error: true), even though no human pressed Escape. The session then parks indefinitely until an operator sends a fresh message.

The interrupt consistently lands mid-execution of a running tool call, not at launch — in the best-documented case an Agent (subagent) call had been running ~17 minutes when interrupted, ruling out a launch-time render race.

Environment

  • Claude Code v2.1.228 – v2.1.233 (events span multiple versions; re-verified on a current binary)
  • macOS 26.5.2, tmux 3.6a
  • Sessions launched detached in tmux: claude -w {worktree} --dangerously-skip-permissions --model {model}; often no client attached at all

Evidence corpus

Nine confirmed events, three repositories, three weeks (July 23 – Aug 7, 2026):

| When (UTC) | Session context | Interrupted during |
|---|---|---|
| 07-23 19:20 | repo A, worktree session | Agent call |
| 07-29 13:29 | repo B, worktree session | Agent call |
| 07-29 19:37 | repo B, same session | Agent call |
| 08-02 12:56 | repo A, worktree session | text-generation turn* |
| 08-03 04:52 | repo A, same session | Agent call |
| 08-03 13:27 | repo A, same session | text-generation turn* |
| 08-05 22:08 | repo B, worktree session | Agent call |
| 08-06 05:14 | repo B, worktree session | Agent call |
| 08-07 15:47 | repo C, worktree session | Agent call |

\* same bare interrupt marker, attached to an ordinary text turn rather than a tool call.

Key facts: 7 of 9 events interrupted an Agent (subagent fan-out) call — the heaviest TUI re-render state. Two events occurred overnight (~1am local) with nobody at the machine and no tmux client attached. The corpus spans three independently-checked-out repositories, ruling out a single stale binary.

Exclusions (each independently checked)

  1. No local guard/daemon. Process audit found nothing that sends keys; the only orchestration tooling active is a read-only pane classifier (tmux capture-pane/has-session only).
  2. No orchestrator key-send in the window. For the best-documented event, all orchestrator tmux send-keys in the surrounding hours targeted a different session with explicit -t, and only ever sent text+Enter — never Escape.
  3. No operator input in the window. Last real operator input was ~45 minutes before the event; the transcript contains no operator text between it and the bare interrupt result.
  4. Not an attached-terminal artifact. Initially hypothesized (one event had an attached, focused client); withdrawn — the class recurs on sessions never attached, including the two overnight events.
  5. Not a fixed prior trigger. An earlier related trigger in our tooling (a status-line handling bug) was fixed before this corpus begins; the class survived that fix.

Hypothesis

The lone ESC reaching Claude Code's input loop does not originate from any agent, orchestrator, or attached terminal. Remaining candidate: Claude Code's own TUI input handling during heavy re-render, specifically around subagent status rendering. Concrete mechanism: terminal query/response cycles — e.g. cursor-position DSR (ESC[6n) and its response — appear on stdin even with no client attached (tmux itself answers such queries). Under heavy re-render the input parser may mis-split an ESC-prefixed report sequence, and the leading, now-isolated ESC byte is read as a bare interrupt keypress.

This is consistent with every element of the corpus: no human required, no attached client required, concentration in Agent fan-outs, multi-version persistence.

Requested behavior

Debounce or validate a bare, lone ESC byte on stdin before treating it as an interrupt while a turn is actively running — e.g. require no trailing bytes within a few milliseconds before committing to the interrupt, so an ESC that is actually the lead byte of a terminal report sequence (cursor-position, focus, or other DSR/CSI responses) is not misread as a standalone interrupt.

Reproduction

Not yet byte-captured; we are arming tmux pipe-pane logging on spawned sessions to catch the sequence during a live recurrence and will attach it here if caught. Happy to provide session transcripts (with the bare [Request interrupted by user for tool use] results) on request.

Full corpus and exclusion evidence are tracked in a private orchestration repo; everything material is reproduced above.

View original on GitHub ↗

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