[BUG] Native installer: in-memory buffering + no progress + 10-min hard timeout + restart-from-zero retries make updates impossible (and look like a deadlock) on slow routes to downloads.claude.ai

Open 💬 0 comments Opened Jun 10, 2026 by houyangzhao

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.170)

What's Wrong?

Summary

On network routes where downloads.claude.ai throughput is below ~370 KB/s, the native installer (claude update / claude install) can mathematically never succeed, and the failure mode looks exactly like a deadlock: zero progress output, the target version file stays at 0 bytes for 10+ minutes, then a silent install_failed. The combination of design choices that causes this:

  1. The entire ~222 MB binary is buffered in memory and only written to disk at the end. The destination file (~/.local/share/claude/versions/<ver>) is created upfront as a 0-byte placeholder, so watching the filesystem shows no progress at all.
  2. No progress indication — the CLI prints Installing Claude Code native build X... and then nothing, for many minutes.
  3. A ~10-minute overall timeout aborts the attempt regardless of whether data is actively flowing. We observed an attempt being killed at ~220 / 222 MB (99%), all buffered data silently discarded.
  4. Retries restart from byte 0 (no Range/resume). With slow throughput every retry also hits the 10-minute ceiling, so 3 retries waste ~30 minutes and 3× the bandwidth, then fail.

Environment

  • macOS arm64 (Darwin 25.5.0), Claude Code 2.1.169 → 2.1.170, native install
  • Network: route to downloads.claude.ai sustains only ~100–250 KB/s, while the legacy GCS endpoint is ~10× faster on the same connection, same moment, same file:
$ curl -r 0-8388607 -o /dev/null -w 'speed=%{speed_download}B/s time=%{time_total}s\n' \
    https://downloads.claude.ai/claude-code-releases/2.1.153/darwin-arm64/claude
speed=257173B/s  (timed out at 30s with 7.7/8 MB)

$ curl -r 0-8388607 -o /dev/null -w 'speed=%{speed_download}B/s time=%{time_total}s\n' \
    https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/2.1.153/darwin-arm64/claude
speed=2160174B/s time=3.88s

Evidence (from live-debugging a stalled claude install 2.1.153)

  • lsof on the stalled installer: healthy ESTABLISHED TLS connections; per-connection counters on our gateway showed data steadily flowing at ~100–250 KB/s — not hung, just slow with zero feedback.
  • lsof shows no temp file open for writing; process RSS grew in lockstep with bytes transferred (reached ~505 MB), confirming full in-memory buffering.
  • Gateway cumulative download counter exceeded the file size (254 MB transferred for a 222 MB file): attempt #1 was killed by the overall timeout at ~220/222 MB and the download restarted from zero.
  • sample of the process: main thread idle in kevent64 (event loop waiting on sockets) — consistent with a slow download, not a deadlock.
  • .last-update-result.json recorded install_failed from a previous day's auto-attempt, matching the same mechanism.

This failure mode actively misleads users into killing the process and filing "updater is deadlocked" reports (we initially mis-diagnosed it that way too). Possibly related: #66213 (desktop app, runaway cumulative downloads from the same CDN — consistent with a "timeout → discard → restart from zero" loop).

Expected Behavior

  • Stream the download to a temp file on disk instead of buffering ~222 MB in memory.
  • Print download progress (bytes or %).
  • Use a stall/idle timeout (no bytes for N seconds) rather than a hard total-duration cap — or at least make the cap generous when data is flowing.
  • Resume retries with HTTP Range requests instead of discarding hundreds of MB.
  • Optionally: keep the GCS endpoint as a fallback, or allow overriding the download base URL via an env var, since it remains reachable and fast on routes where the new CDN is slow.

Steps to Reproduce

  1. Be on a route where downloads.claude.ai sustains < ~370 KB/s (222 MB ÷ 600 s) — common in parts of Asia.
  2. Run claude update or claude install <version>.
  3. Observe: 0-byte version file, no output, ~10 min per attempt, silent retries, eventual install_failed.

---
Investigation performed with Claude Code itself. 🤖

View original on GitHub ↗