No stream-inactivity watchdog: unattended sessions hang forever on wedged API response; headless --print dies terminally on retryable 429/5xx

Status Open
Reported on v2.1.234
Maintainer reply None cached
Activity 1 comment · opened Aug 18, 2026

Summary

Unattended Claude Code sessions on our host repeatedly go permanently silent mid-task. We have now root-caused three operator-visible "stream halt" incidents to two client resilience gaps around API stream failures. Local workarounds have been built three times; the failure class recurs because both gaps are client-side.

Environment

  • Claude Code 2.1.234 (CLI + VS Code extension 2.1.234), Linux 6.8.0-117-generic
  • Models: claude-fable-5 (interactive), claude-opus-5 (headless subprocesses)
  • Usage pattern: long-running interactive tmux sessions + headless claude --print --output-format stream-json worker subprocesses

Defect 1: no inactivity watchdog on an in-flight API stream (interactive)

An interactive session's API response stream wedged mid-response and the client spun on the "Whisking…" spinner for 26+ minutes with no timeout, no retry, and no surfaced error. The session was unattended (tmux); to an operator the stream is simply silent forever. Killing/resuming the session is the only recovery.

Observed today (2026-08-18 ~15:59–16:26 UTC): spinner showed Whisking… (26m 11s · ↓ 60.2k tokens) with zero child processes and no network progress; the turn never completed.

Expected: a stream inactivity timeout (e.g. no bytes for N seconds) that aborts, surfaces a typed error, and retries/resumes — especially critical for unattended/headless operation.

Defect 2: headless --print runs terminate fatally on retryable errors

Headless stream-json runs die terminally on errors that should be retryable, discarding long in-flight tasks:

  • "result":"API Error: Server error mid-response. The response above may be incomplete.", "terminal_reason":"api_error", "api_error_status":null — after 50 turns, 698s of API time, $4.93 spend, the run simply ends (and confusingly reports "subtype":"success" in the result JSON).
  • Three more runs the same day died with "api_error_status":429, "terminal_reason":"api_error" — a rate-limit, i.e. the textbook retryable error, treated as terminal mid-task.

Expected: retry with backoff on 429/5xx mid-run (or a resume mechanism for --print runs), and subtype should not be success when terminal_reason is api_error.

Impact

  • 9 headless worker runs across 2026-08-17/18 ended with terminal_reason:"api_error", several after multi-dollar spend, requiring full re-dispatch.
  • Interactive unattended sessions stall silently 4–7 turns in; a human has to notice and take over. This has happened on 3 consecutive days despite local mitigations (liveness sweeps, heartbeat/first-contact logging, watchdog scripts).

Repro sketch

Long-running unattended session or --print run on a busy account (concurrent subprocess workers). Any mid-response 5xx wedge or 429 reproduces the class; the client behavior (indefinite spinner / terminal death) is deterministic once the stream fails.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗