Background Bash task notification reports exit code 0 when the command exited 1
Background task completion notification reports exit code 0 when the command exited 1
Type: Harness defect (Claude Code)
Severity: High. Silently converts a failing verification run into a passing one.
Channel: github.com/anthropics/claude-code/issues
Reported: 2026-07-25
Environment
- Claude Code, model
claude-opus-5[1m], reasoning effortxhigh - macOS (darwin 25.5.0), zsh
- Project: ~10k-test JavaScript app,
npm run check:ciruns eslint + tsc + jest + stylelint + a build
Summary
A Bash tool call launched with run_in_background: true completed, and the
resulting <task-notification> reported completed (exit code 0) when the
underlying command had exited 1.
Observed four separate times in a single session, every time onnpm run check:ci.
Reproduction
Run any long command that exits non-zero via Bash with run_in_background: true.
To make the true exit code observable independently of the notification, capture it
inside the command:
npm run check:ci > /tmp/checkci.log 2>&1; echo "CHECKCI_EXIT=$?" >> /tmp/checkci.log
Actual vs expected
Notification received:
<task-notification>
<status>completed</status>
<summary>Background command "Run full check:ci in background" completed (exit code 0)</summary>
</task-notification>
Actual content of the log written by the same command:
CHECKCI_EXIT=1
Test Suites: 4 failed, 256 passed, 260 total
Tests: 48 failed, 4 skipped, 10123 passed, 10175 total
Expected: the notification reports exit code 1.
Impact
The assistant treats the notification as authoritative unless told otherwise. In
this session it only avoided shipping a red build because the project's own stored
notes carried an explicit warning to read a logged exit code rather than trust the
wrapper, so it had instrumented the command by hand.
Without that project-specific workaround, the sequence is: run verification in
background, receive "exit code 0", report the work as verified, commit. The failure
is silent and the reporting reads as confident.
Any user relying on background verification runs is exposed to this.
Suggested fix
Propagate the real process exit status into the task notification. If the current
value reflects the notification pipeline's own status rather than the child
process's, that distinction needs to be surfaced explicitly rather than presented
as exit code N.
Workaround for other users
Do not trust the exit code in the notification. Capture it inside the command and
read it from the output:
<command> > log 2>&1; echo "EXIT=$?" >> log