[BUG] Background Bash tasks (run_in_background=true) are sporadically SIGKILLed mid-run by the CLI's task supervision (~1% of dispatches; can corrupt git state)

Open 💬 0 comments Opened Jul 12, 2026 by internunreliable

Environment

  • Claude Code 2.1.207, CLI entrypoint, running inside tmux on Linux (Debian 13, kernel 6.12.94)
  • Sandbox mode enabled (default-on; kills reproduce BOTH sandboxed and with

dangerouslyDisableSandbox: true)

  • Single-user machine, no memory pressure (32G+, memory.max = max on the session scope)

Summary

Bash tool calls dispatched with run_in_background=true are sporadically killed mid-run by
something on the harness side. The task reaches terminal status: killed with a 0-byte output
file and no exit code. Measured over 30 days of session transcripts (1,224 transcript files /
304 sessions, ~28.5k Bash dispatches):

| dispatch shape | dispatched | killed | rate |
| --- | --- | --- | --- |
| background, sandboxed | 965 | 14 | 1.45% |
| background, unsandboxed | 477 | 4 | 0.84% |
| foreground | 27,032 | n/a | ~0.007% lost |

What OS-level evidence shows

We correlated the killed tasks' timestamps with kernel process accounting (acct/dump-acct)
and the kernel journal:

  1. Whole-tree simultaneous signal death. For each kill, every process in the task's tree

(bash + git + git-remote-http + grandchildren) carries the acct "killed by signal" flag
with the same death instant — a process-group SIGKILL. Trap handlers never fire (EXIT traps
produce no output), consistent with SIGKILL specifically.

  1. Not OOM. Zero kernel OOM lines in the journal across the observation window; the session

cgroup has no memory limit. Host memory was fine.

  1. Not a timeout boundary. Kills arrive 28-136 seconds into jobs (one at 317s) — nowhere near

the call's timeout parameter or any documented cap. One separate kill landed at exactly
3600.4s (a cap shape?), while other tasks ran 2h+ untouched.

  1. Unsandboxed variant confirms the mechanism: in one burst, ppid=1 orphaned bash trees

(no PID namespace, children reparented to init) were signal-killed the same way.

What it does NOT correlate with

  • Session activity: in the best-documented case the session made ZERO tool calls between the

dispatch and the kill 60s later — the CLI was idle at the API.

  • Context events: no compaction, no API errors, no turn boundaries at kill instants.
  • Load: concurrent-dispatch count around kills (~1.6 within ±180s) matches the baseline for

completed jobs (1.52).

  • Content/command shape: victims include git push (mid pre-push hook), git commit

(mid pre-commit hook), plain bash test suites, and long-running node processes. Meanwhile a
30-minute polling script survived 257/257 background runs.

  • Temporal pattern: kills are BURSTY — several within a few minutes, then days of silence —

suggesting an episodic supervision state rather than per-job decisions.

Two of the observed kills were session-teardown sweeps (job killed the instant the session
exited) — those look intentional and are fine. The remaining kills are mid-session.

Impact

  • A background git commit/git push killed mid-write corrupts the worktree index (we observed

a phantom-blob cache-tree entry and a truncated ~232-byte index requiring
rm .git/worktrees/<wt>/index && git reset && git add -A to repair).

  • Plugin-spawned workers (e.g. a Codex CLI companion) are killed the same way (13-20% of those

dispatches in our data, likely because they're longer-lived).

  • The task notification reports status: killed with no reason, so agents can't distinguish

"harness policy" from "crash" and waste turns diagnosing.

Expected behavior

Either (a) tracked background tasks are not killed while their session is alive, or (b) the kill
carries a surfaced reason (killed: <resource-policy|supervision-restart|...>) in the task
notification so agents/users can react appropriately.

Reproduction

Nondeterministic (~1% per dispatch); we could not find a deterministic trigger. Highest-yield
repro: dispatch run_in_background=true Bash jobs of 1-5 min duration (e.g. a git push running a
slow pre-push hook) during active multi-tool sessions, and scan the session JSONL for
<task-notification> blocks with <status>killed</status>. Happy to share the transcript-scan
script (joins tool_use dispatches to task notifications and computes per-shape kill rates) and
the raw acct extracts.

Workaround (for anyone else hitting this)

Run loss-intolerant ops (git commit/push, deploys) as FOREGROUND Bash calls with a generous
timeout; reserve run_in_background=true for jobs whose loss only costs a re-dispatch.
Foreground calls were effectively immune in our data (2 lost of 27,032). User-typed ! shell
commands are also unaffected (they never enter the task supervision tree, including when the UI
detaches them after a few minutes).

View original on GitHub ↗