Crash leaves user-spawned background processes orphaned and the terminal stuck in mouse-reporting mode

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Jul 25, 2026

Environment

  • Claude Code 2.1.220 (native/Bun build)
  • Debian GNU/Linux 13 (trixie), kernel 6.12.96+deb13-amd64, x86_64
  • Local terminal session over SSH

What's wrong

The CLI crashed mid-session. Because the crash is uncatchable, no cleanup ran at all, leaving two distinct kinds of damage behind.

1. Orphaned background processes. Two background Bash tasks started earlier in the session survived the crash and kept running, reparented to init (PPID 1):

  • a timeout 72000 .venv/bin/python -m <module> data-import job
  • a tail -f <log> | grep -E --line-buffered ... watcher on that job

I noticed roughly an hour later, when the orphaned watcher was still emitting output into a pipe with no reader. I had to find and kill the process tree by hand (pgrep/ps + kill) from the next session. The new session had no record that these existed.

2. Terminal left in mouse-reporting mode. A second SSH terminal on the same host had hosted the crashed session. After the crash, every mouse movement in it emitted raw SGR mouse reports onto the shell prompt (ESC[<0;38;11M and similar). Claude Code enables mouse tracking at startup and disables it on exit; the crash skipped the restore. No process held the tty — the terminal itself was misconfigured, so there was nothing to kill and nothing in ps to explain it. reset fixed it. Bracketed paste is presumably left stuck the same way.

The second symptom is the more user-visible: it looks like the shell is broken, with no diagnosable cause.

These are filed together because they are one root cause — abnormal exit runs no cleanup — but happy to split if you'd rather track them separately.

What should happen

  • Background tasks started by a session are cleaned up when that session's process dies, or are at minimum detected and offered for cleanup when a new session starts in the same project directory.
  • Terminal modes set by the CLI are restored even on abnormal exit.

Notes on mechanism

Cleanup registered at the JS layer (exit handlers, task teardown) cannot help here by definition — a hard crash or SIGKILL skips it. Fixes that survive an uncatchable death sit below the runtime:

  • prctl(PR_SET_PDEATHSIG, SIGTERM) on spawned children, so the kernel signals them however the parent dies. This is a Linux extension, not POSIX — POSIX has no parent-death notification at all, and macOS needs kqueue/NOTE_EXIT.
  • spawn children into their own process group and kill the group
  • a startup sweep that detects background tasks recorded by a previous session whose PID is gone, and reaps them
  • for the terminal: that same startup sweep could re-emit the mode-reset sequences when it detects a previous session that did not exit cleanly

Related but distinct

There is a cluster of orphaned-process reports, and this one is a different trigger from all of them:

  • #18405 (closed, stale) — orphans on /exit, i.e. the graceful path
  • #71730 — workflow subagents orphaned on connection drop
  • #80885 — scheduled-task sessions leaking processes after being marked complete
  • #80856 — orphaned processes after "bridged process stopped responding"

Every one of those leaks Claude's own subagent processes through a path where JS-level cleanup could still in principle run. This report is about user-spawned Bash background tasks surviving a crash of the runtime itself, where JS cleanup provably cannot run. Fixing any of the above leaves this case untouched.

The common thread is arguably that process supervision is handled ad hoc per exit path, with no crash-survivable mechanism underneath any of them.

Impact

Low frequency — needs a crash and a live background task — but the failure is silent and unbounded in duration. In my case the orphan was a harmless watcher, but the same session also had a ~25-hour data import running against a database. An orphaned writer competing with a restarted one would be a genuine data-corruption hazard, not just resource clutter.

View original on GitHub ↗