[BUG] Exit code 9 death spiral: crash-resume cycles compound streaming memory leak (sequential agents)

Resolved 💬 2 comments Opened Feb 16, 2026 by shayesdevel Closed Feb 16, 2026

Description

Claude Code crashes with exit code 9 (Bun/JSC fatal memory allocation failure) in a previously undocumented failure mode: sequential (not concurrent) agent execution followed by simple bash commands triggers the streaming memory leak, and crash-resume cycles create a compounding death spiral where each resumption makes the next crash faster.

This is distinct from #19378 (concurrent streaming leak) and our earlier #26017 in that:

  1. Agents were run sequentially, not in parallel
  2. Crashes occurred after agent completion, during trivial bash commands
  3. Each crash-resume cycle increased baseline memory, creating a positive feedback loop

Environment

  • Claude Code: v2.1.42 (native Bun/JSC binary)
  • Model: Opus 4.6 (Claude Max subscription)
  • OS: WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2)
  • WSL2 Config: 12GB RAM, 8 processors, 16GB swap

Steps to Reproduce

  1. Start a Claude Code session with moderate initial context (read 5-10 files for project orientation)
  2. Dispatch Opus Task agent A — implementation work producing ~500+ lines of output
  3. Wait for Agent A to complete fully
  4. Dispatch Opus Task agent B — test writing producing ~200+ lines of output
  5. Wait for Agent B to complete fully
  6. Run any bash command that produces streamed output (e.g., pytest tests/ | tail -3)
  7. CRASH: Exit code 9

Death spiral reproduction (after step 7):

  1. Resume session (claude --continue or --resume)
  2. Run any bash command (even echo hello)
  3. CRASH: Exit code 9, faster than step 7
  4. Repeat steps 8-10: each cycle crashes faster

Session Forensics

| Step | Action | Result |
|------|--------|--------|
| 1 | Wake protocol (read ~8 identity files) | OK |
| 2 | Plan agent (haiku) — journal exploration | OK |
| 3 | Plan agent (opus) — design investigation | OK |
| 4 | Release script (trivial) | OK |
| 5 | Agent A (opus) — SDK implementation, ~540 line output | OK |
| 6 | Agent B (opus) — SDK tests, ~37 tests written | OK |
| 7 | pytest ... \| tail -3 | EXIT CODE 9 |
| 8 | Resume + pytest ... \| tail -5 | EXIT CODE 9 |
| 9 | Resume + minimal command | EXIT CODE 9 |
| 10+ | Resume + anything | EXIT CODE 9 |

Root Cause Analysis

Confirmed: The streaming memory leak documented in #19378 is the primary cause.

New finding: Conversation context accumulation is a compounding factor. After two Opus agents complete, their full output (~700+ lines combined) is permanently in the conversation transcript. When a new streaming operation begins (even a simple bash command), the leak starts from a higher baseline. On a 12GB WSL2 system, this leaves essentially zero headroom.

Death spiral mechanism:

Crash 1: baseline_context(high) + streaming_leak(1GB/s) > 12GB → exit 9
Resume 1: baseline_context(high) + resume_overhead → even higher baseline  
Crash 2: higher_baseline + streaming_leak → exit 9 (faster)
Resume 2: even_higher_baseline + resume_overhead → critical
Crash 3: critical_baseline + any_streaming → instant exit 9

Each --resume loads the full previous transcript into the new process. The conversation context from prior agent outputs is not compacted or trimmed.

Why Existing Mitigations Failed

All documented mitigations from prior issues were followed:

| Mitigation | Applied? | Result |
|------------|----------|--------|
| Stagger agents (no concurrent) | Yes — fully sequential | Still crashed |
| Limit to <3 Opus agents | Yes — only 2 agents | Still crashed |
| Use haiku for lightweight work | Yes — Plan agents used haiku | Still crashed |
| Pipe output through tail | Yes — tail -3, tail -5 | Still crashed |

Expected Behavior

  1. Streaming response handler should free chunks incrementally (bounded memory)
  2. --resume should compact/trim conversation context to reduce baseline memory
  3. At minimum: detect approaching memory limits and either GC aggressively or warn the user
  4. Crash-resume should not create a death spiral — each resume should be no worse than the previous state

Related Issues

| Issue | Status | Relationship |
|-------|--------|-------------|
| #19378 | OPEN (stale) | Root cause: streaming memory leak |
| #26017 | OPEN | Our concurrent-agent crash report |
| #24480 | OPEN | SIGKILL 5-10x daily since Opus 4.6 |
| #14052 | OPEN | Task tool orchestrator 15GB+ leak |
| #24583 | OPEN | 36GB single process on v2.1.37 |

Changelog fixes that did NOT resolve this: v2.1.14, v2.1.16, v2.1.23, v2.1.30 all addressed specific memory scenarios but left the core streaming leak unfixed.

Impact

  • Severity: Critical for orchestration-heavy workflows
  • Frequency: Deterministic — any session with 2+ Opus agent outputs will crash on subsequent bash commands (on 12GB systems)
  • Productivity: Death spiral makes sessions unrecoverable; must start fresh
  • User base: Affects Task/sub-agent orchestration, especially on memory-constrained systems (WSL2, smaller laptops)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗