router-for-me/CLIProxyAPI · error
antigravity token exchange: decode response: %w
Error message
antigravity token exchange: decode response: %w
What it means
The token exchange returned 2xx but the response body is not decodable as a TokenResponse JSON (access_token/refresh_token fields). Causes: empty body despite 200, HTML/HTML-fragment body, or a schema where the token fields are nested differently.
Source
Thrown at internal/auth/antigravity/auth.go:176
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)
if err != nil {
return "", fmt.Errorf("antigravity userinfo: create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("User-Agent", o.shortUserAgent())
resp, errDo := o.httpClient.Do(req)View on GitHub (pinned to 78f0c4079e)
Solutions
- Log the raw body (redacting tokens) when decode fails to see what was actually returned
- If a proxy intercepted the response, bypass it or trust its CA and retry with a fresh code
- If the schema changed, update TokenResponse fields/json tags
Defensive patterns
Strategy: try-catch
Try / catch
var typeErr *json.UnmarshalTypeError
if errors.As(err, &typeErr) {
// schema drift: token JSON shape changed
} else if strings.Contains(err.Error(), "decode response") {
// interception or truncation — retry with a fresh code
} Prevention
- Verify Content-Type on 2xx token responses
- Detect and bypass proxies that rewrite OAuth responses
When it happens
Trigger: A proxy returns 200 with an auth-page body; upstream changes token response shape; body truncated by a read timeout mid-decode.
Common situations: Captive portals / proxy interception on the token endpoint; partial responses on flaky links.
Related errors
- antigravity userinfo: decode response: %w
- antigravity token exchange: read response: %w
- antigravity userinfo: read response: %w
- marshal request body: %w
- antigravity token exchange: create request: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/dcf4110b8152b6d5.
Report an issue: GitHub.