router-for-me/CLIProxyAPI · error
claude oauth tls: dial upstream: %w
Error message
claude oauth tls: dial upstream: %w
What it means
The uTLS-based OAuth transport failed at the raw TCP/proxy dial stage, before any TLS bytes flowed. dialTLSContext first connects through the configured (possibly proxy-aware) dialer; a failure here means network-level connectivity to the OAuth host (or to the configured proxy) is broken. The wrap includes the dialer's own error (DNS, refused, timeout, proxy failure).
Source
Thrown at internal/auth/claude/utls_transport.go:212
roundTripper.transport = &http.Transport{
ForceAttemptHTTP2: false,
DialTLSContext: roundTripper.dialTLSContext,
}
return roundTripper
}
func (t *utlsRoundTripper) dialTLSContext(ctx context.Context, network, addr string) (net.Conn, error) {
var (
conn net.Conn
err error
)
if contextDialer, ok := t.dialer.(proxy.ContextDialer); ok {
conn, err = contextDialer.DialContext(ctx, network, addr)
} else {
conn, err = t.dialer.Dial(network, addr)
}
if err != nil {
return nil, fmt.Errorf("claude oauth tls: dial upstream: %w", err)
}
host, _, errSplit := net.SplitHostPort(addr)
if errSplit != nil {
if errClose := conn.Close(); errClose != nil {
log.Debugf("claude oauth tls: close failed connection: %v", errClose)
}
return nil, fmt.Errorf("claude oauth tls: split upstream address: %w", errSplit)
}
tlsConn := tls.UClient(conn, newClaudeOAuthTLSConfig(host, t.sessionCache), tls.HelloCustom)
if errPreset := tlsConn.ApplyPreset(claudeOAuthTLSClientHelloSpec()); errPreset != nil {
if errClose := tlsConn.Close(); errClose != nil {
log.Debugf("claude oauth tls: close connection after preset failure: %v", errClose)
}
return nil, fmt.Errorf("claude oauth tls: apply ClientHello: %w", errPreset)
}
handshakeCtx := ctx
if handshakeTimeout, _ := ctx.Value(claudeRefreshHandshakeTimeoutContextKey{}).(time.Duration); handshakeTimeout > 0 {View on GitHub (pinned to 78f0c4079e)
Solutions
- Check the wrapped error: DNS failure → fix resolv.conf/DNS; connection refused/timeout → verify egress path to the OAuth host.
- Set or fix HTTPS_PROXY/HTTP_PROXY/NO_PROXY so the OAuth dialer uses the corporate proxy (and ensure the proxy allows CONNECT to the OAuth hosts).
- Test raw reachability: `curl -v https://api.anthropic.com` (with and without -x $HTTPS_PROXY) from the same host/container.
- In containers, verify DNS and egress with a simple Go or curl probe before running the login/refresh flow.
Example fix
# before unset HTTPS_PROXY # direct egress blocked by firewall # after export HTTPS_PROXY=http://proxy.corp.example:3128 export NO_PROXY=localhost,127.0.0.1
Defensive patterns
Strategy: retry
Validate before calling
conn, err := net.DialTimeout("tcp", "api.anthropic.com:443", 5*time.Second)
if err != nil { return fmt.Errorf("egress to OAuth host blocked: %w", err) }
conn.Close() Try / catch
resp, err := oauthClient.Do(req)
if err != nil && strings.Contains(err.Error(), "dial upstream") {
if isTransientNetErr(err) { time.Sleep(time.Second); resp, err = oauthClient.Do(req) }
if err != nil { return fmt.Errorf("check DNS/proxy egress: %w", err) }
} Prevention
- Verify HTTPS_PROXY/NO_PROXY match your network's real egress path before login/refresh.
- Add a startup egress probe to api.anthropic.com:443 in restricted environments.
When it happens
Trigger: The Claude OAuth HTTP client dialing api.anthropic.com/claude.ai through direct or proxy dialing when: DNS resolution fails, the network is down, a firewall drops egress, or HTTPS_PROXY/ALL_PROXY points at a dead/unreachable proxy.
Common situations: Corporate environments where egress requires a proxy but HTTPS_PROXY is unset (direct connections blocked); misconfigured proxy env vars (typo'd host, wrong port, proxy requiring auth); DNS failures in containers with broken resolv.conf; firewalls blocking the OAuth endpoints specifically.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- fetch Claude OAuth %s: %w
- kimi: device code request failed: %w
- antigravity token exchange: execute request: %w
- execute request: %w
- claude oauth tls: handshake upstream: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/4a0a601b319d4238.
Report an issue: GitHub.