Background Bash task SIGTERMed 51s after turn went idle — pressure reaper firing without its 30-minute-idle precondition?
Environment
- Claude Code 2.1.220, interactive TUI session
- macOS (Darwin 25.6.0), Apple Silicon, 32 GB RAM
- No
BASH_DEFAULT_TIMEOUT_MS/BASH_MAX_TIMEOUT_MSanywhere; no hooks with kill logic;CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAPnot set at the time
What happened
A long test suite (make test-rebuild, ~18 minutes) was launched via the Bash tool with run_in_background: true and no timeout. The assistant's turn then ended and the session sat idle. 51 seconds later the task's whole process tree received SIGTERM, and the session got a task-notification with status: killed ("Background command ... was stopped"). No TaskStop was ever called (verified across every transcript for the project), and the user took no action.
Timeline (from the session transcript, file birth/mtimes, and the unified log):
| Time (PDT, 2026-08-01) | Event |
|---|---|
| 21:19:31 | Background task launched |
| 21:23:26 | Assistant turn ends; session idle |
| 21:23:50 | Unified log: memorystatus idle-exit of an unrelated 3 MB Apple extensionkitservice — routine housekeeping, with memorystatus_available_pages=1034822 (≈15.8 GB available) |
| 21:24:17 | Task tree SIGTERMed: python dies mid-write, uv forwards TERM and exits 143, make prints Error 143; harness notification status: killed |
The killed status is the tell that this was the harness's own stop path: natural exits in the same session — including failing ones — consistently read completed (exit code N), and an external pkill of the leaf process would have let make exit normally with code 2.
Why this looks like the memory-pressure reaper misfiring
The documented behavior (v2.1.193+) is that background shells are terminated under OS memory pressure only after the session has been idle ≥30 minutes. Here the session had been idle 51 seconds, and there was no actual pressure — 15.8 GB available at the moment of the preceding memorystatus event, which was an idle-exit of a 3 MB service, not a pressure escalation.
Control experiments, same machine, same suite, same idle-while-running conditions:
- Rerun 1: ran 18m10s to completion. Zero memorystatus events in the log window.
- Rerun 2 (with a 5-second memory sampler alongside): ran 18m27s to completion. Minimum available memory 7.34 GB (23% of 32 GB) — less than half the headroom present at the kill moment — zero swap growth (1830 MB → 1830 MB),
kern.memorystatus_levelnever below 45, and again zero memorystatus events in the window.
So: tighter memory + no memorystatus event → survived twice; looser memory + one routine memorystatus event during a brief idle → killed. The discriminating variable is the presence of a memorystatus event, not memory conditions.
Hypothesis: the reaper subscribes to macOS memorystatus/memory-pressure notifications and terminates background shells on any event arriving while the session is momentarily idle, without enforcing the documented 30-minute idle threshold or checking that the event is an actual pressure escalation.
Expected vs. actual
- Expected: the background task keeps running; reaping only under real memory pressure after ≥30 minutes idle, per the documentation.
- Actual: task killed 51 seconds after the turn went idle, with ~16 GB free, in response to (at most) routine memorystatus housekeeping chatter.
Workaround
CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP=1 in settings env.