CLI hangs mid-execution on macOS (Apple Silicon, Opus 4.6 1M) — debug log shows dead event loop with only version timer surviving
Environment
- Claude Code: 2.1.92
- OS: macOS 26.3.1 (Apple M4 Max)
- Model: Opus 4.6 (1M context)
- Shell: zsh
- Plugin: CELLM (13 hooks across SessionStart, UserPromptSubmit, PreToolUse, PostToolUse)
- MCP servers: 5 (cellm-oracle, playwright, stitch, context7, ide)
Symptom
CLI freezes mid-execution (not between prompts). No keyboard input accepted — Enter, Ctrl+C, Ctrl+O, ESC all have no effect. The process does NOT recover without human interaction. Observed hangs of 6+ hours.
This happens daily, multiple times per session. It is not occasional.
Debug Log Evidence
Analyzed ~/.claude/debug/{session}.txt (18,271 lines). Built 5-minute activity heatmap:
14:10: 1084 lines ########################################
14:15: 836 lines ########################################
...
15:10: 57 lines #####
15:15: 2 lines [!] SPARSE <-- only version check
15:20-15:35: 0 <-- DEAD: no window at all
15:40: 67 lines ###### <-- user interaction revived it
15:45: 2 lines [!] SPARSE
16:00: 1275 lines ########################################
...
16:20: 85 lines ########
16:25-16:45: 0 <-- DEAD: 25 min gap
16:50: 2 lines [!] SPARSE <-- only version check
16:55-17:15: 0 <-- DEAD: 30 min gap
17:20: 2 lines [!] SPARSE <-- only version check
17:25: 1205 lines ######################################## <-- revived by input
Key observation: During "dead" windows, the ONLY debug output is the 30-minute Checking for native installer update timer. This is a background setInterval that survives the hang. No hooks execute, no MCP traffic, no input processing — the main event loop is blocked.
The 2-line SPARSE windows contain exactly:
2026-04-06T16:52:23.286Z [DEBUG] Checking for native installer update to version 2.1.92
2026-04-06T16:52:23.289Z [DEBUG] Found 2.1.92 at /Users/murillo/.local/bin/claude, skipping install
JSONL Correlation
Session JSONL shows the same gaps align with assistant -> system(file-history-snapshot) -> [GAP] -> user — meaning the CLI finished an assistant response, wrote the snapshot, then went dead before accepting the next prompt.
Frequency
In this single 5-hour session: 5 dead windows totaling ~100 minutes of lost time.
Relation to Existing Issues
This matches #33949 (SSE streaming hang, no client-side timeout) and #26224 (thinking freeze 5-20min). The debug log evidence here adds:
- Proof the event loop is blocked — not just "no tokens". Zero debug output except the version timer.
- Recovery requires human interaction — the CLI does NOT self-recover.
- Occurs mid-execution — not during idle/thinking. The assistant had just completed a response.
Reproduction
Not deterministic. Occurs during normal development sessions with:
- Multiple tool calls (Read, Edit, Bash, MCP)
- Plugin with hooks (but issue #33949 reports same without plugins)
- Opus 4.6 with 1M context
Expected Behavior
- Client-side timeout on SSE streams (e.g., 60s no-data timeout)
- Heartbeat detection for dead connections
- Event loop should never block indefinitely on a single stream reader
Workaround
None reliable. ESC sometimes works (per #33949), but in our case no key input is accepted during the hang.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗