router-for-me/CLIProxyAPI · error
fetch Claude OAuth %s: %w
Error message
fetch Claude OAuth %s: %w
What it means
Returned by ClaudeAuth.fetchOAuthControlPlaneJSON when the GET to the Anthropic OAuth control-plane endpoint fails at the transport level, wrapping the httpClient.Do error. The request is deliberately Axios-shaped (User-Agent axios/1.15.2, Accept-Encoding including br, Connection: close) to mirror Claude Code's client; intermediaries that filter on such headers, plus ordinary DNS/TLS/proxy failures, land here. A nil-body or non-2xx outcome does NOT — those are separate errors.
Source
Thrown at internal/auth/claude/anthropic_auth.go:243
func (o *ClaudeAuth) fetchOAuthControlPlaneJSON(ctx context.Context, endpoint, accessToken, label string) ([]byte, error) {
if o == nil || o.httpClient == nil {
return nil, fmt.Errorf("fetch Claude OAuth %s: HTTP client is nil", label)
}
accessToken = strings.TrimSpace(accessToken)
if accessToken == "" {
return nil, fmt.Errorf("fetch Claude OAuth %s: access token is empty", label)
}
req, errRequest := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if errRequest != nil {
return nil, fmt.Errorf("create Claude OAuth %s request: %w", label, errRequest)
}
applyClaudeOAuthAxiosHeaders(req)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Cache-Control", "no-cache")
resp, errDo := o.httpClient.Do(req)
if errDo != nil {
return nil, fmt.Errorf("fetch Claude OAuth %s: %w", label, errDo)
}
defer func() {
if errClose := resp.Body.Close(); errClose != nil {
log.Errorf("failed to close Claude OAuth %s response body: %v", label, errClose)
}
}()
body, errRead := readClaudeOAuthResponseBody(resp)
if errRead != nil {
return nil, fmt.Errorf("read Claude OAuth %s response: %w", label, errRead)
}
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
return nil, fmt.Errorf("fetch Claude OAuth %s failed with status %d", label, resp.StatusCode)
}
return body, nil
}
// FetchOAuthProfile retrieves the account identity associated with an OAuth access token.
func (o *ClaudeAuth) FetchOAuthProfile(ctx context.Context, accessToken string) (*OAuthProfile, error) {View on GitHub (pinned to 78f0c4079e)
Solutions
- Unwrap with errors.As to *url.Error and identify DNS vs dial vs TLS vs context.Canceled
- Test reachability with curl -v https://api.anthropic.com/api/oauth/profile from the same environment
- Fix proxy settings in config.yaml or bypass the intercepting middlebox
- Retry after checking https://status.anthropic.com for outages
Defensive patterns
Strategy: retry
Try / catch
profile, err := auth.FetchOAuthProfile(ctx, token)
if err != nil {
var urlErr *url.Error
if errors.As(err, &urlErr) && !errors.Is(urlErr.Err, context.Canceled) {
profile, err = retryWithBackoff(func() (*OAuthProfile, error) {
return auth.FetchOAuthProfile(ctx, token)
})
}
if err != nil { return err }
} Prevention
- Pre-flight check connectivity to api.anthropic.com before starting login
- Validate proxy-server settings; transport errors here often come from proxy config
- Check Anthropic status page before retrying during suspected outages
When it happens
Trigger: api.anthropic.com unreachable (DNS/firewall); TLS interception rejecting the connection; proxy misconfiguration applied via util.SetProxy; ctx cancelled during the request; an intermediary resetting connections flagged as non-browser traffic.
Common situations: Corporate proxies blocking api.anthropic.com; Great-Firewall-style regional interference; transient Anthropic outages; VPN split-tunneling excluding the API host.
Related errors
- claude oauth tls: dial upstream: %w
- antigravity token exchange: execute request: %w
- execute request: %w
- claude oauth tls: handshake upstream: %w
- token exchange request failed: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/0f91858655ea2ef9.
Report an issue: GitHub.