anthropics / anthropics/claude-code

[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)

オープン
#89,495 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
area:bash area:core bug data-loss has repro platform:macos
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

## 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 `-p` without execution semantics). None covers a **top-level `claude -p` session 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):

1. **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.
2. **Default `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` in `-p` mode** (overridable): long commands then block in-turn or fail visibly at the tool timeout. Verified working as a per-run mitigation (repro below).
3. **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

```shell
# 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):**

```sh
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):**

```sh
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-json` traces for both runs if useful.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Start by running the two provided `claude -p` reproduction commands with `CLAUDE_CODE_AUTO_BACKGROUND_TIMEOUT_MS=10000`, comparing the control and `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` treatment. Trace the print-mode background-task lifecycle and the background-message selection, including `CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS`. Done means a backgrounded command in print mode either completes and reports its output or exits with a visible failure, never a false success with lost work.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
macos, python, shell, zsh
領域
cli, devtools, testing
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
45/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。