router-for-me/CLIProxyAPI · error
antigravity token exchange: execute request: %w
Error message
antigravity token exchange: execute request: %w
What it means
The Antigravity token exchange HTTP request was constructed but httpClient.Do failed. The wrapped error is typically *url.Error carrying the underlying cause: DNS failure, connection refused, TLS handshake error, timeout, or context cancellation.
Source
Thrown at internal/auth/antigravity/auth.go:154
// ExchangeCodeForTokens exchanges authorization code for access and refresh tokens
func (o *AntigravityAuth) ExchangeCodeForTokens(ctx context.Context, code, redirectURI string) (*TokenResponse, error) {
data := url.Values{}
data.Set("code", code)
data.Set("client_id", ClientID)
data.Set("client_secret", ClientSecret)
data.Set("redirect_uri", redirectURI)
data.Set("grant_type", "authorization_code")
req, err := http.NewRequestWithContext(ctx, http.MethodPost, TokenEndpoint, strings.NewReader(data.Encode()))
if err != nil {
return nil, fmt.Errorf("antigravity token exchange: create request: %w", err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, errDo := o.httpClient.Do(req)
if errDo != nil {
return nil, fmt.Errorf("antigravity token exchange: execute request: %w", errDo)
}
defer func() {
if errClose := resp.Body.Close(); errClose != nil {
log.Errorf("antigravity token exchange: close body error: %v", errClose)
}
}()
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
bodyBytes, errRead := io.ReadAll(io.LimitReader(resp.Body, 8<<10))
if errRead != nil {
return nil, fmt.Errorf("antigravity token exchange: read response: %w", errRead)
}
body := strings.TrimSpace(string(bodyBytes))
if body == "" {
return nil, fmt.Errorf("antigravity token exchange: request failed: status %d", resp.StatusCode)
}
return nil, fmt.Errorf("antigravity token exchange: request failed: status %d: %s", resp.StatusCode, body)
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Inspect the wrapped url.Error's Unwrap() to identify DNS vs TLS vs timeout
- Verify egress to the token endpoint (curl the TokenEndpoint URL) from the same environment
- If behind a MITM proxy, add its CA to the client's trust store or configure the proxy on httpClient
- Retry the exchange — OAuth code exchange is a one-shot operation, so retry quickly and note the code may expire
Defensive patterns
Strategy: retry
Try / catch
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// retry once with a fresh code; code exchange is one-shot so get a new code if it was consumed
} Prevention
- Verify egress to Google OAuth endpoints before running the flow
- Trust corporate proxy CAs in the http.Client
- Set a generous but finite timeout on the exchange
When it happens
Trigger: POST to the Google token endpoint fails due to no network, DNS resolution failure, corporate proxy blocking accounts.google.com, TLS interception with an untrusted CA, or the context deadline expiring mid-request.
Common situations: Running the OAuth flow in sandboxed CI without egress; self-signed MITM proxy not in the system trust store; transient network drop; firewall blocking Google OAuth endpoints.
Related errors
- execute request: %w
- antigravity userinfo: execute request: %w
- fetch Claude OAuth %s: %w
- claude oauth tls: dial upstream: %w
- token exchange request failed: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/2970c92153e49bc7.
Report an issue: GitHub.