[BUG] -p mode: Bash auto-background tells the model "You will be notified when it completes" — a promise print mode never keeps (silent data loss)
Preflight Checklist
- [x] I have searched existing issues. Closest matches are adjacent, not this bug: #73453 (headless exit with pending Agent-tool children; ceiling not applied), #80834 (same false copy, but scoped to subagents' Bash tasks), #82151 (turn-end vs live-work signal, interactive session), #81476 (Monitor tool copy in headless), #59864 (closed precedent: tools advertised in
-pwithout execution semantics). None covers a top-levelclaude -psession with an auto-backgrounded Bash command. - [x] This is a single bug report
- [x] I am using the latest version of Claude Code (reproduced on 2.1.245 today)
What's Wrong?
In non-interactive print mode (claude -p), a Bash tool call that exceeds the auto-background threshold is moved to the background and the model is told, verbatim: "You will be notified when it completes."
In interactive sessions that promise is kept — the harness re-invokes the model on completion. In print mode the session terminates the moment the model ends its turn: a model that trusts the harness and ends its turn to wait dies mid-task, the backgrounded command is killed with the process, and the CLI exits with is_error: false whose result is a mid-work status note. The work is silently lost while the envelope reads success.
The kicker: the truthful message already ships in the binary. The 2.1.245 background-message builder contains a second variant:
"If it exits while you are still working you will be notified, but it is terminated when you give your final response and no notification can follow that — so do not end your turn to wait for it; if you need its result, wait for it before giving your final response."
…but it is selected only for commands owned by a synchronous subagent (the backgroundEndsWithFinalResponse / reaped-at-final-response path, whose schema doc reads: "…terminated when that agent gives its final response; absent when the command survives (main loop, async subagents)"). In print mode the main-loop command does not survive — the classification is wrong there, so the false promise is emitted.
What Should Happen?
Any one of these (smallest first):
- Truthful message in print mode — select the already-shipping "terminated when you give your final response / do not end your turn to wait" variant when the session is non-interactive. One condition change; removes a whole class of silent mid-task deaths.
- Default
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1in-pmode (overridable): long commands then block in-turn or fail visibly at the tool timeout. Verified working as a per-run mitigation (repro below). - Actually keep the promise: hold the event loop open while background tasks are pending and deliver the notification. The machinery appears to exist — the binary carries
CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS("…terminating. Set CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 to wait indefinitely.") — but it did not hold the process for an auto-backgrounded Bash task (see timing below; cf. #73453 for the Agent-tool analogue).
Error Messages/Logs
# Control run on 2.1.245 (full pipeline wall time: 18.4s — the process exited
# ~8s after the 10s auto-background trigger; the 40s command never finished):
{
"is_error": false,
"subtype": "success",
"num_turns": 3,
"result": "The command is running in the background. It will complete in approximately 40 seconds. I'll report the output once it finishes."
}
# "ctl-marker-2245" is never printed anywhere. Exit code 0.
Steps to Reproduce
Deterministic, ~18 seconds end to end. CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MS is only used to trigger the auto-background quickly; the default threshold reproduces identically, just slower.
1. Bug (control):
CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MS=10000 \
claude -p 'Run exactly this shell command and then report its full output verbatim: sleep 40 && echo ctl-marker-2245' \
--model haiku --output-format json --permission-mode bypassPermissions
Observed: at ~10s the Bash call is auto-backgrounded and the tool result tells the model "You will be notified when it completes." The model ends its turn to wait; the CLI prints the envelope above and exits at ~18s. The marker is never delivered.
2. Correct behavior exists behind an env var (treatment):
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MS=10000 \
claude -p 'Run exactly this shell command and then report its full output verbatim: sleep 25 && echo fix-marker-2245' \
--model haiku --output-format json --permission-mode bypassPermissions
Observed: the Bash call blocks in-turn and result contains fix-marker-2245 (is_error: false, 33s wall). So the capability to avoid the loss already ships; the print-mode default is the foot-gun.
Real-world impact
We found this when a claude -p review subagent (long-effort model) ran a slow test suite; the suite was auto-backgrounded; the harness told the model it would be notified; the model ended its turn "waiting for its notification" (verbatim from its transcript) and the process exited. 19 minutes of analysis were lost; the parent pipeline received exit 0 with a status note as the final answer. Any headless pipeline that trusts is_error: false receives a truncated deliverable with no failure signal — a silent-data-loss class, not cosmetic. Comment 3 on #73453 (terminal_reason: "completed", result = "Good progress — 7 of 20 agents have completed so far. Waiting…") shows the same failure shape via the Agent tool.
Claude Model
Other — haiku for the minimal repro; original incident hit a long-effort seat. Model-independent: any model that believes the tool result reproduces it.
Is this a regression?
I don't know
Claude Code Version
2.1.245 (Claude Code) — repro verified 2026-08-25 on the darwin-arm64 npm dist binary; also reproduced same day on 2.1.233 (native installer).
Platform
Anthropic API
Operating System
macOS (Darwin 25.6.0, arm64)
Terminal/Shell
Non-interactive/CI environment (claude -p, zsh parent shell)
Additional Information
- Env knobs confirmed in the shipped binary and by behavior:
CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MS(trigger),CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1(working mitigation),CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS(present in binary; did not apply to this Bash case). - Related: #73453, #80834, #82151, #81476; #59864 is closed precedent for aligning print-mode tool copy with print-mode semantics.
- Happy to provide the full
--output-format stream-jsontraces for both runs if useful.