[BUG] Bash tool returns empty output for long-running streaming processes (totalBytes stuck at 0)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The Bash tool intermittently returns empty output for long-running streaming processes (SSE streaming CLI tools that run for minutes), even though the streaming progress display (fullOutput in session JSONL) shows output accumulating normally during execution.
This is a different failure mode from #26562. In #26562, the pipe closes ~270ms too early after process exit. In this bug, the pipe never connects — totalBytes stays at 0 from the very first progress heartbeat, progress heartbeats die mid-run, there's a minutes-long gap with no progress events, and then the tool result comes back completely empty.
Diagnostic Evidence from Session JSONL
Analyzed 3 sessions running a CLI tool that streams SSE responses over several minutes. Each session had at least one failed Bash invocation:
Failed calls — consistent signature:
| Metric | Session 1 (call 2/3) | Session 2 (call 1/2) | Session 3 (call 1/8) |
|---|---|---|---|
| totalBytes in progress | 0 (every heartbeat) | 0 (every heartbeat) | 0 (every heartbeat) |
| fullOutput in progress | 723 chars (growing) | 2553 chars (growing) | 1828 chars (growing) |
| Progress heartbeats | Stopped at 97s | Stopped at 157s | Stopped at 327s |
| Gap before tool result | 7m 25s (no events) | 3m 34s (no events) | 47s (no events) |
| Final tool result | 0 bytes (empty) | 0 bytes (empty) | 0 bytes (empty) |
Successful calls (retries in same session) — for comparison:
| Metric | Session 1 retry | Session 2 retry | Session 3 retry |
|---|---|---|---|
| totalBytes in progress | 14799 (growing normally) | 8153 (growing normally) | 8192 (growing normally) |
| fullOutput in progress | 4044 chars | 4049 chars | 4084 chars |
| Progress heartbeats | Continuous until exit | Continuous until exit | Continuous until exit |
| Gap before tool result | <1s | <1s | <1s |
| Final tool result | 14677 bytes | 8263 bytes | 11752 bytes |
Key Observations
totalBytes: 0from the first heartbeat — the stdout capture pipe was never connected, not "closed too early"fullOutputaccumulates normally — a separate capture path (PTY/streaming display) works fine, so the process IS producing output- Progress heartbeats die mid-run — at 97s, 157s, and 327s respectively, well before the 600s timeout
- Minutes-long dark period — the process continues running but Claude Code receives no progress events
- Retries always succeed — the second invocation in the same session has normal
totalBytesand returns full output - Short/fast commands unaffected —
which,cat,lsin the same session return results fine (they complete before any race can manifest)
How This Differs from #26562
| | #26562 | This bug |
|---|---|---|
| Trigger | Statusline saturating event loop / nested claude subprocesses | Long-running SSE streaming process, no statusline involvement |
| Failure mode | Pipe closes ~270ms too early after process exit (exit vs close race) | Pipe never connects — totalBytes: 0 from first heartbeat |
| Threshold | ~270ms delay before stdout | No threshold — fails on first invocation regardless of timing |
| Duration | Milliseconds | Minutes-long runs |
| Progress heartbeats | N/A (short commands) | Die mid-run, minutes-long gap before empty result |
| Repro | /bin/sleep 0.3 && echo "hello" | Any long-running streaming CLI, intermittent on first invocation per session |
Two Separate Output Capture Paths
The session JSONL reveals that Claude Code has two independent output capture mechanisms:
fullOutput(inbash_progressevents) — works correctly, accumulates streaming outputtotalBytes→ final tool result — broken on failed calls, never receives any data
When totalBytes is stuck at 0 from the start, the final tool result is always empty, even though fullOutput captured the output. This suggests the result-path pipe fails to initialize before the process starts writing.
Steps to Reproduce
- Run any long-running streaming CLI via the Bash tool (e.g., an SSE streaming process that runs for several minutes)
- Use a 600000ms timeout
- Observe that the first invocation intermittently returns empty output
- Retry — second invocation succeeds
Any CLI that starts producing stdout quickly after launch and streams output over minutes could trigger this.
What Should Happen?
The Bash tool should return the same output that was visible during streaming progress (fullOutput). If the primary output pipe fails, the tool should fall back to the fullOutput buffer rather than returning empty.
Error Messages/Logs
No errors — the tool silently returns empty output with exit code 0. The only diagnostic signal is totalBytes: 0 in session JSONL progress events.
Claude Model
Opus 4.6
Is this a regression?
I don't know
Claude Code Version
2.1.68
Platform
Anthropic API
Operating System
macOS (Darwin 25.3.0, arm64)
Terminal/Shell
fish (via iTerm2)
Additional Information
Related: #26562 (same symptom family but different failure mode and trigger)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗