[BUG] macOS: long sessions die with ECONNRESET — macOS TCP send-buffer default (autosndbufmax=4MB) bursts the growing context upload; one sysctl fixes it

Status Open
Maintainer reply None cached
Activity 2 comments · opened Aug 16, 2026

Summary

On macOS, long Claude Code sessions progressively fail with Unable to connect to API / ECONNRESET. The root cause is not the network — it is the macOS TCP send-buffer autotuning default (net.inet.tcp.autosndbufmax = 4 MB) interacting with Claude Code's request shape.

Claude Code uploads the entire conversation context as a single request body on every turn. As a session grows, that body crosses a threshold where macOS bursts multiple megabytes into the uplink at once, overruns the queue at the LAN→WAN step-down, and the connection is reset. Everything else on the same machine stays perfectly healthy, which is exactly why this gets misdiagnosed as "slow internet".

One sysctl fixes it completely:

sudo sysctl -w net.inet.tcp.autosndbufmax=262144

Why this is easy to misdiagnose

The failure is selective. Measured on the affected machine while Claude Code was dying:

| Workload | Result |
|---|---|
| Downloads | 6.2 MB/s — fine |
| LAN transfer | 11.7 MB/s — fine |
| Web browsing, RSS fetches, GitHub, WebFetch | fine |
| Uploads ≤ 512 KB | fine |
| Single uploads ≥ 1 MB | dead |

Almost nothing in normal desktop use pushes several MB upstream in one shot — browsing, downloads and streaming are all downstream, and large uploads are usually chunked. Claude Code is one of the few tools that routinely does it, and it does so more as the session lengthens.

So the user experience is "only Claude is broken, my internet is fine", which points investigation at the account, the app, or the ISP. Everything else working is not evidence against this bug — it is the signature of it.

I lost two days to exactly this misdiagnosis before measuring correctly.

Root cause

macOS grows the TCP send buffer up to autosndbufmax (4 MB by default). When that much data is handed to the NIC at once, it leaves at LAN line rate and overruns the shallow queue at the uplink step-down. The connection never recovers and resets.

Two details from the XNU source that matter:

  • Send-buffer autotuning has no RTT term. The growth conditions in tcp_output.c are receive-window headroom, buffer 7/8 full, and sendwin >= unacked — no BDP estimate. (The receive side does use rcv_srtt in tcp_sbrcv_grow().) So the buffer climbs toward 4 MB regardless of how small the actual BDP is.
  • Pacing does not apply to ordinary sockets. tp->t_pacer is only engaged for TCP_CC_ALGO_PRAGUE_INDEX or when inp_max_pacing_rate != UINT64_MAX, and in_pcb.c initialises every PCB to UINT64_MAX. Regular CUBIC sockets get no pacing, so nothing smooths the burst.

The 4 MB default is relatively recent — comparing xnu release tags, the effective ceiling went 512 KB (Mavericks) → 1 MB (Sierra) → 2 MB (Catalina) → 4 MB from Big Sur, where the trigger also changed to mem_actual >= 4GB, which every modern Mac passes.

Evidence

1. It is a burst problem, not a bandwidth problem

Same 1 MB payload, only the send rate varied:

| curl --limit-rate | Result |
|---|---|
| 100 KB/s | HTTP 200 · completed · 10.25 s |
| 300 KB/s | HTTP 200 · completed · 3.43 s |
| 600 KB/s | HTTP 200 · completed · 1.72 s |
| 1000 KB/s | HTTP 200 · completed · 1.03 s |
| unlimited | died at 15.04 s (982,878 / 1,048,576 bytes sent) |

Deliberately throttling to 1 MB/s completes in 1 second; removing the limit kills the connection. A bandwidth shortage cannot produce this.

2. A/B/A on the sysctl

| Step | autosndbufmax | Observation |
|---|---|---|
| A | 262144 | Normal — 3.18 MB artifact upload succeeded |
| B | 4194304 (default) | Claude Code conversation stopped mid-session |
| A′ | 262144 | Recovered immediately |

Unlimited uploads after the fix:

| Size | Before | After |
|---|---|---|
| 1 MB | died at 15.04 s | 0.11 s · 9.5 MB/s |
| 2 MB | died | 0.19 s · 11.2 MB/s |
| 3 MB | died | 0.28 s · 11.4 MB/s |
| 10 MB | died | 0.88 s · 12.0 MB/s |

The link is ~12 MB/s. My initial (wrong) measurement of "85 KB/s uplink" was the broken state being measured — off by two orders of magnitude.

3. Competing hypotheses excluded

No shaper exists on the machine — verified with admin rights:

| Candidate | Check | Result |
|---|---|---|
| dummynet pipes | dnctl list | empty |
| pf shaping | pfctl -s info | dummynet counter 0 over 73 days uptime |
| pf rules | pfctl -sr, -a com.apple/* -sr | stock Apple anchors only |
| Application firewall | socketfilterfw --getglobalstate | disabled |
| System extensions | systemextensionsctl list | 0 |
| Proxy | scutil --proxy | none |
| Network Link Conditioner | prefPane | not installed |
| Router per-device limits | admin UI, all menus | feature does not exist on the unit |

The Tahoe ECN upload-stall bug is excluded. There are community reports of macOS 26.x stalling uploads, fixed with net.inet.tcp.ecn_initiate_out=0 — same OS, same direction, same "stalls shortly after starting", overlapping hardware. It looked like a strong alternative. Held ECN off and varied only the buffer:

| ecn_initiate_out | autosndbufmax | Result |
|---|---|---|
| 0 | 4194304 | broken |
| 0 | 262144 | fine |
| 1 (default) | 262144 | fine |

The symptom follows the buffer, not ECN.

"Windows on the same router is fine" is not usable as evidence — Windows disables ECN by default, so both hypotheses explain it. Noting this because it is a tempting but non-discriminating observation.

Environment

  • Mac mini Mac16,10, 16 GB RAM
  • macOS 26.3.1 (25D2128)
  • Wired Ethernet, gigabit LAN, residential fibre (~12 MB/s up when healthy)
  • RTT to api.anthropic.com 4.2 ms, claude.ai 4.7 ms (domestic CDN edge)
  • Reproduced identically against speed.cloudflare.com/__up and api.anthropic.com, so it is not endpoint-specific

Reproduction

  1. On a Mac with sysctl net.inet.tcp.autosndbufmax = 4194304 (the default)
  2. Run a Claude Code session until the conversation context is large (roughly ≥ 1 MB per request)
  3. Requests begin failing with Unable to connect to API / ECONNRESET, ~15 s per attempt
  4. sudo sysctl -w net.inet.tcp.autosndbufmax=262144 — recovers immediately, no restart needed
  5. Restore 4194304 — symptom returns

Standalone check without Claude Code:

head -c 1048576 /dev/urandom > 1mb.bin
curl -o /dev/null -X POST --data-binary @1mb.bin https://speed.cloudflare.com/__up
curl -o /dev/null --limit-rate 1000k -X POST --data-binary @1mb.bin https://speed.cloudflare.com/__up

If the first dies and the second completes, this is the bug.

Trade-off of the workaround

Capping the send buffer caps single-connection throughput at buffer ÷ RTT:

| Destination RTT | Ceiling at 256 KB |
|---|---|
| 5 ms | ~51 MB/s — far above any residential link |
| 50 ms | ~5 MB/s |
| 150 ms | ~1.7 MB/s — the only range where it actually costs something |

Anthropic endpoints resolve to a nearby edge here (4–5 ms), so the cap is invisible in practice. It does not persist across reboot.

Suggested fixes

Ordered by how much they'd help, most first:

  1. Chunk large request bodies, or set inp_max_pacing_rate on the socket so XNU's pacer engages. This removes the burst at the source and would fix it for every affected user without any system tuning.
  2. Detect and surface it. A repeated ECONNRESET at a consistent wall-clock point, on macOS, with a large request body, is a recognisable signature. Even a hint in the error text — "large request body failed to upload; see <doc>" — would save people days.
  3. Document the workaround in the macOS troubleshooting guide.

Note on prevalence

The only public precedent I could find is a June 2026 write-up — and it is also a Claude Code user, with the identical sysctl fix, the same 15–16 s reset, and the same "throttling makes it complete" behaviour. Their conditions differed (German DSL, 22 ms RTT, 24 Mbps up), so this is not specific to low-latency links.

Two independent cases both being Claude Code is unlikely to be reporting bias, because the failure is selective to large single-shot uploads — the machine is otherwise entirely healthy. Claude Code is simply one of the few consumer tools that generates that traffic shape, and it does so more the longer a session runs.

That suggests other macOS users may be hitting this and attributing it to their connection. The 4 MB default has shipped on every Mac since Big Sur; what changed recently is the workload.

View original on GitHub ↗

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