Native update/install fails with 'socket connection was closed unexpectedly' behind proxy — undici TLS incompatibility
Description
claude update and claude install consistently fail with:
Error: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()
This occurs when running behind a proxy (system proxy enabled). The issue is specific to the bundled undici fetch() inside claude.exe — all other methods of accessing the same URL work fine.
Environment
- OS: Windows 11
- Claude Code version: 2.1.153 (native install)
- System Node.js: v24.15.0
- Proxy: HTTP/HTTPS proxy on localhost
Reproduction
- Run behind a proxy
- Execute
claude updateorclaude install - Fails immediately with the socket error
What works vs. what doesn't
| Method | Result |
|--------|--------|
| Browser access to downloads.claude.ai | ✅ Works |
| curl https://downloads.claude.ai/claude-code-releases/latest | ✅ Works |
| Node.js https.get() (system Node v24) | ✅ Works |
| Node.js fetch() (system Node v24) | ✅ Works |
| claude.exe internal fetch() (bundled Node) | ❌ Fails |
Root cause analysis
The TLS handshake fails specifically inside the bundled undici in claude.exe. This was confirmed by:
# System Node.js fetch works fine
node -e "fetch('https://downloads.claude.ai/claude-code-releases/latest').then(r => r.text()).then(console.log)"
# Output: 2.1.153 ✅
# But claude.exe fails on the same URL
claude update
# Error: socket connection was closed unexpectedly ❌
Setting NODE_TLS_REJECT_UNAUTHORIZED=0 does not resolve the issue for claude.exe, suggesting the problem is deeper than certificate validation — likely an incompatibility between the bundled undici version's TLS implementation and certain proxy configurations.
Additional context
- The same
claude.exeversion (2.1.153) works on one machine but fails on another with the same system Node.js version (v24.15.0), suggesting the bundled Node.js/undici version may differ or there's a subtle environmental difference in how the binary interacts with the proxy. - Related issues: #60133 (SO_KEEPALIVE analysis), #37801 (update fails but curl works), #13498 (GCS timeout)
Suggestion
Consider adding proxy support to the native updater (respecting HTTP_PROXY/HTTPS_PROXY environment variables) or falling back to https.get when fetch() fails.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗