router-for-me/CLIProxyAPI · error
antigravity token exchange: request failed: status %d
Error message
antigravity token exchange: request failed: status %d
What it means
The Antigravity token exchange endpoint answered with a non-2xx status and an empty body, so only the status code can be reported. Common statuses: 400 (invalid/expired/reused authorization code, redirect_uri mismatch, bad client_id/secret), 401, 403, or a 5xx from Google's OAuth service.
Source
Thrown at internal/auth/antigravity/auth.go:169
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)
}
var token TokenResponse
if errDecode := json.NewDecoder(resp.Body).Decode(&token); errDecode != nil {
return nil, fmt.Errorf("antigravity token exchange: decode response: %w", errDecode)
}
return &token, nil
}
// FetchUserInfo retrieves user email from Google
func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) {
accessToken = strings.TrimSpace(accessToken)
if accessToken == "" {
return "", fmt.Errorf("antigravity userinfo: missing access token")
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil)View on GitHub (pinned to 78f0c4079e)
Solutions
- Restart the full OAuth flow to get a fresh authorization code and exchange it immediately
- Verify redirectURI passed to ExchangeCodeForTokens matches exactly the redirect used in the authorize URL (scheme, host, port, path)
- Confirm ClientID/ClientSecret constants are current for the Antigravity app
- If 5xx persists, check the Google OAuth status page and retry later
Defensive patterns
Strategy: validation
Validate before calling
if time.Since(codeIssuedAt) > 5*time.Minute {
// code near its ~10min lifetime — get a new one before exchanging
} Try / catch
if strings.Contains(err.Error(), "token exchange: request failed: status 400") {
// restart OAuth flow: code expired, used, or redirect mismatch
} Prevention
- Exchange the authorization code immediately after the callback
- Ensure redirectURI matches the authorize request exactly
- Never replay an already-exchanged code
When it happens
Trigger: Exchanging an authorization code that expired (~10 min lifetime) or was already used once; redirect_uri not matching the one in the authorize request; wrong client_id/client_secret constants; Google OAuth outage returning 503 with empty body.
Common situations: Re-running the OAuth callback manually with a stale code; clock skew plus code expiry; the app registered redirect URI differing (port/path) from redirectURI passed in.
Related errors
- antigravity token exchange: request failed: status %d: %s
- antigravity userinfo: request failed: status %d
- antigravity userinfo: request failed: status %d: %s
- request failed with status %d: %s
- antigravity token exchange: create request: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/868238f14c63f99e.
Report an issue: GitHub.