Requests silently stall for 900s with no error or retry logged

Status Open
Reported on v2.1.260
Maintainer reply None cached
Activity 2 comments · opened Sep 9, 2026

Requests silently stall for 900s with no error or retry logged

Reporter environment: Claude Code 2.1.260 (claude-desktop entrypoint),
Windows 11 Pro 26200, Node 24.18.1, default ANTHROPIC_BASE_URL, no proxy,
Windows Defender only, no MCP servers.

---

Summary

Requests are accepted and fully acknowledged at the TCP level by Cloudflare, and
no HTTP response is ever returned. The client waits 900 seconds, then retries
and succeeds. Nothing is logged — no error, no retry, no timeout event — because
from the client's perspective nothing failed.

Two separable defects:

A. Infrastructure. Requests reaching Cloudflare EWR are acknowledged and
never answered. The same client on the same machine, minutes later via a
different ISP reaching Cloudflare BOS, is completely clean.

B. Client. A 900-second silent wait, with no log entry of any kind, is
indistinguishable from the product being slow. This is what makes A invisible.

---

Why this is worth fixing beyond the one user

Defect B means defect A produces no error message and no telemetry. From the
user's seat, Claude simply stops responding for fifteen minutes and then continues
as if nothing happened. There is nothing to search for, nothing to report, and
nothing in any log.

This reporter spent three weeks believing their cable modem was faulty, replaced
nothing, and nearly requested an ISP hardware swap. Anyone on an affected route
who is less persistent would reasonably conclude the product is unreliable and
stop using it. Because nothing is logged, that would never surface as a bug report.

---

Evidence

1. Wire capture during a live 30-minute stall

pktmon, filtered to 160.79.104.10 and 2607:6bc0::10 on port 443, headers
only. Captured ~24 minutes into a stall that ran 16:30:24Z → 17:00:23Z.

Flow [client]:60073 > 2607:6bc0::10:443:

 0.0 - 1.8 s   Tx   907,582 bytes uploaded (the request)
 1.8 - 1.9 s   Rx   every byte ACKed, ZERO retransmissions
 3.3 - 3.5 s   Tx   three window updates
 3.5 - 63.5 s  --   60 seconds of complete silence
63.5 s         Tx   1-byte TCP keepalive probe
63.5 s         Rx   keepalive ACKed IMMEDIATELY

total response data bytes received: 0

Across the whole capture: 690 packets, 19 flows, 0 retransmissions.

This rules out, at the packet level: packet loss, path blackholing, NAT teardown,
upload stalling, the client failing to send, and client-side deadlock. The
connection was demonstrably alive in both directions throughout — the keepalive
was answered instantly at minute 24 of the stall.

The request arrived, was acknowledged, and no response was produced.

2. Cloudflare colo differs by network, and tracks the failures

https://api.anthropic.com/cdn-cgi/trace, same machine, minutes apart:

| network | family | colo | observed stalls |
|---|---|---|---|
| Spectrum (cable) | IPv4 | ORD | untested |
| Spectrum (cable) | IPv6 | EWR | all observed stalls; every hung flow |
| T-Mobile (cellular) | IPv4 | BOS | 0 |
| T-Mobile (cellular) | IPv6 | BOS | 0 |

api.anthropic.com resolves to a single A and a single AAAA record, identical on
both networks — so this is anycast/BGP path selection, not DNS steering.

Control that isolates the datacenter rather than the address family: the cellular
network runs 12 concurrent IPv6 connections to 2607:6bc0::10 with zero
stalls. IPv6 → BOS is healthy. IPv6 → EWR is not.

Route detail: the two families take different transit. IPv4 stays inside the
ISP's own backbone to the Cloudflare handoff and lands on ORD; IPv6 leaves via a
third-party transit provider (Zayo, AS6461) and lands on EWR.

3. Stall durations are quantized at exactly 900 s

Measured across ~4 months of local transcripts by finding tool_result entries
with no assistant reply for ≥120 s:

903.1  903.2  903.4  904.5  907.7  909.2  911.1  913.7  914.4  914.7   = 1 x 900
1807.5  1810.8                                                          = 2 x 900
2709.0                                                                  = 3 x 900

Thirteen events, every one landing 3–15 s past a multiple of 900 s. API_TIMEOUT_MS
is set to 900000 in the environment injected by the desktop app. The overshoot
is the reconnect-and-respond after it fires.

A second quantized value appears at exactly 120.0 s (three instances,
to the tenth of a second), suggesting a separate stream-idle timer.
CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS exists as a knob and was not set.

4. Nothing is logged

The stalled session's transcript contains, for a 30-minute stall:

connection retries : 0
api errors         : 0

The retry mechanism works — a different session logged an ECONNRESET retry
(source: connection_retry) the same afternoon. The stalled session logged
nothing, because the socket stayed Established and TCP raised nothing.

Frequency measured locally: ~3 events per 1,000 assistant messages on the
affected route; 0 per 4,485 on the clean one.

---

What would help

  1. Investigate EWR accepting requests and not returning responses.
  2. Log the timeout. A 900-second wait that produces no log entry is

untraceable by users and invisible to telemetry. Even a debug-level "request
exceeded API_TIMEOUT_MS, retrying" would have made this a ten-minute
diagnosis instead of a three-week one.

  1. Reconsider the 900-second default for the desktop entrypoint, or surface

progress. The failure is rare; the 15-minute silence is what makes it severe.

  1. Consider a liveness check on long-silent streams — the connection is

healthy and answering keepalives, so the client cannot distinguish "still
thinking" from "will never answer."

---

Caveats, stated honestly

  • Colo readings are one sample per network per family. Cloudflare anycast

assignment can vary with load, time and routing.

  • EWR is not proven broken. What is shown: observed failing flows went there,

and the clean network does not.

  • Port-to-PID attribution for flow .60073 could not be made retroactively. That

it belongs to the stalled session is inference from timing and payload size
(907 KB is consistent with that session's 3.35 MB conversation gzipped).

  • Modem + IPv4 (ORD) is untested — it is merely different from EWR.

View original on GitHub ↗

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