Bash tool background/timeout-promoted child processes on Windows never signal completion even after finishing and writing valid output

Status Open
Reported on v2.1.259
Maintainer reply None cached
Activity 0 comments · opened Sep 3, 2026

Environment:

  • Claude Code CLI 2.1.259
  • Windows 11 Pro 10.0.26200
  • Bash tool backend: Git Bash (POSIX sh)
  • Reproduced with long-running Python/CUDA subprocesses (PyTorch model loading, RTX 4090)

Summary:
When the Bash tool runs a long Python/CUDA subprocess in the background — either via explicit run_in_background: true, or via automatic promotion after the foreground command exceeds its timeout — the child process can finish all of its real work (print its final summary, write a complete and valid output file) and then never exit. It sits alive indefinitely at flat CPU (no thread activity), and Claude Code's own background-task completion notification never fires. Force-killing the process by PID immediately causes the tracked background task to report "completed, exit code 0" — meaning the harness truly was just blocked waiting on process exit.

Reproduction (3 separate instances in one session):

  1. ./scripts/benchmark/run_benchmark.sh ... --config-name base_63q ... | tail -60 run in the foreground, no run_in_background flag. Exceeded the 600s default timeout and was auto-promoted to background (task bqb3ts3bx). Underlying python.exe (PID 33996, started 13:19:41) wrote a complete, valid JSON result by 13:24 (~5 min runtime), then sat at flat CPU (202.81 CPU-s, 0 delta over an 8s sample) for 25+ more minutes with no notification, until manually killed at ~13:49 — notification fired immediately after.
  2. Same script, --config-name base_133q, started explicitly with run_in_background: true, stdout/stderr redirected to a file (> log 2>&1, no pipe). Task b7ymnxpai. PID 32796 (started 13:33:54) wrote complete valid output by 13:44 (~10 min runtime), then sat at flat CPU (414.81 CPU-s, 0 delta over 8s) for 5+ minutes with no notification, until manually killed.
  3. Same script, --config-name base_fsim --f-via-similar, run_in_background: true, redirected to file. Task brxwm2lgh. PID 29276 (started 13:49:23) actively used CPU while genuinely working (confirmed by rising CPU across repeated samples), printed its final "Overall: PASS" summary and wrote complete output at 13:53, then immediately went flat-CPU (0 delta over 5s) with no notification, until manually killed — notification fired immediately after.

Common factors:

  • All three are long-running Python/CUDA subprocesses (PyTorch + CUDA model loading/inference).
  • Reproduces regardless of whether backgrounding was automatic (timeout promotion) or explicit (run_in_background: true).
  • Reproduces regardless of whether stdout was piped (| tail) or redirected to a file.
  • In every case, killing the orphaned PID by hand is what unblocks the notification — the harness's own tracking, not the script, is what's stuck.

Impact: Without noticing external signals (GPU utilization, log tail content, output-file existence), there is no way to tell a backgrounded task actually finished. The agent/user must manually detect completion out-of-band and kill the process by PID, defeating the purpose of the background-task notification system for this class of workload.

Root cause: Not confirmed. Leads worth checking: a lingering non-daemon thread in the PyTorch/CUDA teardown path on Windows that never joins; the harness holding an stdio handle/pipe to the child open without ever detecting EOF; or the harness's Windows process-exit detection not correctly tracking a Git-Bash-spawned, backgrounded/detached child process tree.

View original on GitHub ↗