Two separate bugs cause spurious 'Interrupted' dialog on WSL2 (clipboard \x03 + npm update-check SIGCHLD)
Bug: Two separate mechanisms cause spurious "Interrupted" dialog in Claude Code on WSL2
Environment
- OS: WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2)
- Claude Code version: 2.1.79
- Terminal: Reproduced in both VS Code integrated terminal AND Windows Terminal
- Shell: bash
---
Summary
Claude Code has two distinct bugs that both surface as the "Interrupted · What should Claude do instead?" dialog firing unexpectedly. They interact in a self-perpetuating loop that makes Claude Code effectively unusable once triggered.
I spent the majority of multiple session limits — and a significant chunk of my weekly usage limit — tracing this myself using strace, because the interruptions made it impossible to investigate the bug with the tool that has the bug. I'm filing this in the hope that Anthropic can fix it so other users don't face the same cost.
---
Bug #1: Raw Ctrl+C byte (0x03) in pasted clipboard content triggers interrupt handler
Severity
High — self-perpetuating, makes the tool unusable
What happens
Claude Code's terminal input handler treats a raw \x03 byte on the TTY fd as a Ctrl+C interrupt, even when it arrives inside bracketed paste markers (\x1b[200~ ... \x1b[201~). Bracketed paste mode exists specifically to prevent this — input within those markers should be treated as literal text, not control input.
Confirmed via strace
Captured on terminal fd 25:
read(25, "\33[200~<paste content>", 65536) <- bracketed paste START
read(25, "\33[201~", 65536) <- bracketed paste END
read(25, "\3", 65536) = 1 <- 0x03 read 6ms later -> interrupt fires
Why it's self-perpetuating
- Session gets interrupted →
\x03ends up in terminal scroll buffer - User copies terminal output to provide context in a new session →
\x03silently enters clipboard along with visible text - User pastes into new session →
\x03arrives on TTY fd → interrupt fires again - Repeat indefinitely
The user has no visible indication that their clipboard contains a control character. The interrupt fires after the paste completes, so it's not obvious what caused it.
Expected behaviour
Input received within bracketed paste markers (\x1b[200~ / \x1b[201~) should never trigger the interrupt handler, regardless of byte content. This is the entire purpose of bracketed paste mode.
Workaround
Sanitize clipboard before pasting terminal output into Claude Code:
xclip -o | tr -d '\000-\011\013-\037\177' | xclip
---
Bug #2: Background npm update-check subprocess death triggers foreground task interrupt
Severity
High — fires on a ~22–25 second cycle, making the tool unusable after the first interrupt
What happens
Claude Code spawns npm view @anthropic-ai/claude-code@latest version --prefer-online as a background subprocess to check for updates. When this subprocess exits (SIGCHLD), something in Claude Code's subprocess/task management logic incorrectly interprets the subprocess death as a signal to interrupt the foreground task, firing the "Interrupted" dialog.
This fires on every task start, ~22–25 seconds in (matching the npm registry round-trip time). After the first interrupt (however caused), every attempt to continue work is interrupted again ~25 seconds later by the update check completing.
Confirmed via strace
- Normal "heartbeat" child processes die every ~1 second with no interrupt triggered
- The npm update-check child process death correlates exactly with each spurious interrupt event
- No SIGINT, SIGHUP, SIGTERM, or SIGWINCH is delivered to the main Claude Code process at interrupt time — the trigger is purely internal to the Node.js process
Expected behaviour
A SIGCHLD from a background version-check subprocess should never interrupt a foreground user task. Background housekeeping work should be completely invisible to the user.
Workaround / Fix applied
Setting DISABLE_AUTOUPDATER=1 in ~/.claude/settings.json via the env key prevents the update-check subprocess from being spawned and eliminates this trigger entirely:
{
"env": {
"DISABLE_AUTOUPDATER": "1"
}
}
---
Interaction between the two bugs
Bug #1 creates the first interrupt. Bug #2 then fires every ~25 seconds indefinitely, preventing recovery. The combination makes the session completely unusable and forces a restart — at which point Bug #1 is likely to trigger again if the user pastes any context from the interrupted session.
---
Investigation cost
I want to flag clearly: diagnosing these bugs required running multiple strace sessions (some over 10 minutes, one capturing 1.1MB of data), analysing raw binary output, and iterating across many restarts — all while the tool being diagnosed kept interrupting the investigation. This consumed the majority of multiple session context limits and a significant portion of my weekly usage limit.
The irony of having to use Claude (via the claude.ai web interface, which doesn't share the bug) to help analyse Claude Code's own strace output should not be lost on the team. These bugs create a compounding cost: each restart loses context, each interrupted session wastes tokens, and the self-perpetuating nature of Bug #1 means users who don't know the clipboard sanitization workaround will keep hitting it indefinitely.
I'd appreciate acknowledgement that this is a meaningful user cost, not just a minor inconvenience.
---
Additional notes
- The strace investigation also identified that combining
-e readwith-f(follow forks) in strace causes trace files to balloon to 1.5GB+, which independently crashed Claude Code during the investigation. This is a WSL2/resource issue, not a Claude Code bug, but worth noting. - Claude Code's update check uses
AbortSignal.timeout(5000)in the source, suggesting a 5-second timeout is intended. In practice the subprocess was observed to run for 20–30 seconds before dying, suggesting the timeout is not functioning correctly on this system. This may be a separate issue.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗