Bash tool output suppressed when child process spawns `claude -p`
Bug Description
When a command executed via the Bash tool spawns claude -p (pipe mode) as a child process, all stdout and stderr output from the entire Bash session becomes invisible to the Bash tool. This includes output written before the claude -p subprocess is spawned.
Reproduction
Minimal repro — output visible (no claude -p)
Run this via the Bash tool in a Claude Code session:
echo "hello from bash"
Result: "hello from bash" is visible in the tool output. ✅
Minimal repro — output suppressed (with claude -p)
echo "before claude"
claude -p "say hi" --max-turns 1
echo "after claude"
Result: The Bash tool returns zero output. Neither "before claude", the claude response, nor "after claude" are visible. ❌
The data is written to the fds — verified by redirecting stderr to a file and reading it separately:
echo "before" >&2
claude -p "say hi" --max-turns 1 >&2 2>&1
echo "after" >&2
Reading the redirect file confirms all output was produced. The Bash tool simply doesn't return it.
Controls that prove it's specific to claude -p
| Command | Output visible? |
|---------|----------------|
| sleep 3 as child process | ✅ Yes |
| claude --version as child process | ✅ Yes |
| claude -p "say hi" --max-turns 1 as child process | ❌ No |
| echo "before" && claude -p "say hi" --max-turns 1 | ❌ No (even "before" is lost) |
Attempted workarounds (none worked)
2>&1redirection- Piping through
cat - Wrapping in a subshell
- Running via
node -eor separate script instead ofbun stdio: ['pipe', 'pipe', 'pipe']on child spawn- Closing inherited fds 3-255 via shell wrapper, perl, python
FD_CLOEXEC detached: trueon child spawnBun.spawninstead of Nodechild_process.spawn
Workaround that does work
Redirect stderr to a file in the Bash command, then read the file with the Read tool in a separate step:
# Bash tool call
bun my-script.ts 2>/tmp/output.txt
# Then use Read tool on /tmp/output.txt
Root Cause Hypothesis
Investigation of the file descriptors inside the Bash tool session:
- fd 0: socket
- fd 1: file (stdout capture)
- fd 2: file (stderr capture)
- fd 3: pipe (appears to be the Bash tool's "done" signal/monitoring pipe)
- fd 4: file
When fd 3 was explicitly closed in the parent process, partial output became visible ("before" appeared), confirming fd 3 is involved in the output capture mechanism. The claude binary in pipe mode likely inherits and interferes with fd 3 (or other control fds), disrupting the Bash tool's ability to collect output from the captured fd 1/fd 2 files.
The claude binary in pipe mode presumably does something special with inherited file descriptors (perhaps scanning/closing/redirecting them) that non-pipe-mode claude --version does not.
Impact
Any tool or workflow that spawns claude -p from within a Bash tool call loses all output visibility. This affects:
- AI code review tools that invoke
claude -pas a reviewer subprocess - Multi-agent orchestration where a parent claude session uses the Bash tool to run
claude -pfor subtasks - Any CLI tool that shells out to
claude -pand is itself invoked from the Bash tool
The data is actually produced (provable via file redirects), so this is purely an output capture/reporting bug in the Bash tool, not a data loss issue.
Environment
- Claude Code version: 2.1.55
- OS: macOS 15.7.4 (Darwin 24.6.0 arm64)
- Shell: zsh
- Bun: 1.3.6
- Node: v25.2.1
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗