API edge RSTs /v1/messages when time-to-first-header exceeds ~15s — large cold prompts (>~90K tokens) fail deterministically through all retries

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 0 comments · opened Aug 28, 2026

Summary

api.anthropic.com's edge kills any /v1/messages connection with a TCP RST when the first response byte (headers included) takes longer than ~15.0s to arrive. Large cold prompts — in our case Opus 4.5 resumes above ~90-105K uncached input tokens — exceed that prefill time deterministically. The CLI then retries up to 10 times, each retry re-uploading the same cold prompt into the same wall, so the failure is unrecoverable by design: ~6 minutes of retries, surfaced as api_retry with error: "unknown", error_status: null and finally API Error: Unable to connect to API (ECONNRESET).

For a long-running agent daemon on Claude Code (subscription auth, pinned 2.1.226, macOS), this manifested as: every session dies permanently once its context crosses ~105K input tokens, because every resume of it hits >15s TTFB. One such session cost us 43 hours of downtime before we root-caused it.

Packet-level evidence

Reproduced twice under tcpdump with a real heavy --resume (~330K-token session, ~90K cold tokens per resume). Timeline of one killed attempt (client → 160.79.104.10:443):

  • t+0.00s SYN → t+0.01s SYN-ACK → TLS; full 355KB request body uploaded and ACKed by t+0.10s (upload is not the problem)
  • Server sent only its 2,783-byte TLS handshake — zero application bytes, no HTTP headers
  • 14.99s of silence
  • RST from 160.79.104.10

Why we're confident the RST is genuinely from the remote edge and not a router/middlebox forgery:

  1. TTL 55 on the RST — identical to every legitimate server packet (a router-forged RST would show the router's hop distance)
  2. IP-id continuity — the RST's IP id directly continues the server's own counter (…22103, 22104 → 22105)
  3. TCP timestamp clock continuity — RST TSval = last-ACK TSval + 14,984ms, on the server's own clock
  4. Reproduces at 15.01s ± 0.1s across attempts, identically over IPv4 (NATed) and IPv6 (no NAT) via Happy Eyeballs alternation — a home NAT timer can't explain the v6 deaths
  5. Control probe: a deliberately stalled incomplete request body to the same host survives 90s+ untouched — this is a response-header/upstream timeout that fires only after a complete request, not a path idle timer

Why the CLI makes it worse

  • All 10 retries re-upload the same cold prompt; each faces the same prefill wall, so retries can never succeed. Retry budget (~6 min) is pure waste.
  • The error surfaces as connection-level (ECONNRESET, error_status: null), which reads as network flakiness — we spent days blaming the router. Distinguishing "edge killed a slow-prefill request" from genuine unreachability (e.g. by noting the request body fully uploaded and the TLS session established) would save operators a lot of misdiagnosis.
  • Retry gaps in our production tapes correlate smoothly with context size (0-1 retries below 85K input tokens; 15-17 at 90-107K; hard 10/10 failure above ~105K), which may help reproduce.

Asks

  1. Raise (or make configurable) the edge's time-to-first-header timeout for /v1/messages — 15s is below the prefill time of large cold prompts on slower models, well within the documented 1M context window.
  2. In the CLI: consider not burning the full retry ladder when the request body fully uploaded and the connection died pre-headers at a consistent interval — or at least surface a distincter error than ECONNRESET.

Happy to provide the pcap timelines or run further instrumented repros. Environment: Claude Code 2.1.226 (pinned), macOS (Mac mini), subscription OAuth, wired ethernet; reproduced on Opus 4.5; same 15s kill observed with other models (the wall's token threshold shifts with prefill speed — Opus 5 tolerated ~125K).

View original on GitHub ↗