Bash tool permanently broken (exit 1, no output) after a killed background task
Summary
Bash tool becomes permanently broken (every invocation returns exit code 1 with no stdout/stderr) after a long-running background Bash task is killed by the harness for exceeding its timeout. The tool's persistent session state appears to be torn down with the killed process and never recovers; only restarting the Claude Code session restores Bash. All other tools (Read, Write, Edit, etc.) continue to work normally.
Steps to reproduce
- Launch a Bash invocation with
run_in_background: trueand a polling loop that runs longer than the configuredtimeout. For example:
``bash``
# Bash tool call, timeout: 240000 ms, run_in_background: true
launchctl start com.user.water-meter
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
state=$(launchctl print "gui/$(id -u)/com.user.water-meter" 2>&1 \
| grep "^ state =" | head -1 | awk '{print $3}')
echo "[$i] state=$state"
[ "$state" = "not" ] && break
sleep 10
done
- The harness eventually kills the task; the task-notification arrives with
<status>killed</status>.
- From that point on, ANY subsequent Bash invocation in the same session — even
echo hi— returns exit code 1 with completely empty output (no stdout, no stderr).
Expected behavior
A killed background task should not leave the Bash tool in an unrecoverable state. Either:
- Subsequent Bash invocations should spin up a fresh shell as if nothing happened, or
- The tool should surface a clear error explaining what happened and suggest a remedy.
Actual behavior
> echo alive
(Exit code 1)
> ls
(Exit code 1)
> pwd
(Exit code 1)
> date
(Exit code 1)
No output at all. The tool returns "Exit code 1" with no body, even with dangerouslyDisableSandbox: true. The only fix is to terminate Claude Code and start a new session.
Diagnostics gathered before reporting
- Verified no project hooks:
~/.claude/settings.jsononly has theme + marketplace, nohooksblock. Project repos have no.claude/settings.json. - Checked the per-session CWD tracking file referenced in earlier successful Bash invocations (e.g.,
/tmp/claude-84c9-cwdfrom a priorpwd -P >| /tmp/claude-<id>-cwdline in the wrapped shell). The file no longer exists —Readreports "File does not exist". This is consistent with the persistent shell process having been killed alongside the polling loop. - Other tools work fine in the same session (Read, Write, Edit, ScheduleWakeup, ToolSearch).
- Tried
dangerouslyDisableSandbox: true— still exit code 1, no output.
The failure mode is silent: there is no indication to the model that the tool is broken until it tries to run something. A model under time pressure could spend many turns retrying or "debugging" a permanently-broken tool.
Environment
- macOS Tahoe (26.0) on Apple Silicon
- mosh-over-Tailscale → SSH → tmux → claude (kiosk-like persistent session)
- Session was long-running (~12 hours) before the kill
Suggested mitigations
- Detect this state and surface a clear error (e.g., "Bash tool state lost after background task termination — start a new session or run /reset-tool-state").
- Recover automatically by spawning a fresh persistent shell on the next invocation.
- Avoid coupling the persistent shell's lifetime to any individual background-task process group.
Workaround used during the session
Wrote shell scripts to /tmp/*.sh via the Write tool and asked the user to invoke bash /tmp/<script>.sh from a Terminal on the host. Awkward for an iPad user (no easy copy/paste from the Claude Code terminal) but unblocked finishing the work.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗