router-for-me/CLIProxyAPI · error
antigravity userinfo: request failed: status %d: %s
Error message
antigravity userinfo: request failed: status %d: %s
What it means
The userinfo endpoint returned a non-2xx status and the body text is included. Google typically returns JSON such as {"error":{"code":401,"message":"Invalid Credentials"}}, which identifies whether the token is invalid, expired, or lacks scope.
Source
Thrown at internal/auth/antigravity/auth.go:213
if errDo != nil {
return "", fmt.Errorf("antigravity userinfo: execute request: %w", errDo)
}
defer func() {
if errClose := resp.Body.Close(); errClose != nil {
log.Errorf("antigravity userinfo: 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 "", fmt.Errorf("antigravity userinfo: read response: %w", errRead)
}
body := strings.TrimSpace(string(bodyBytes))
if body == "" {
return "", fmt.Errorf("antigravity userinfo: request failed: status %d", resp.StatusCode)
}
return "", fmt.Errorf("antigravity userinfo: request failed: status %d: %s", resp.StatusCode, body)
}
var info userInfo
if errDecode := json.NewDecoder(resp.Body).Decode(&info); errDecode != nil {
return "", fmt.Errorf("antigravity userinfo: decode response: %w", errDecode)
}
email := strings.TrimSpace(info.Email)
if email == "" {
return "", fmt.Errorf("antigravity userinfo: response missing email")
}
return email, nil
}
// FetchProjectID retrieves the project ID for the authenticated user via loadCodeAssist
func (o *AntigravityAuth) FetchProjectID(ctx context.Context, accessToken string) (string, error) {
userAgent := o.shortUserAgent()
loadReqBody := map[string]any{
"metadata": antigravityLoadCodeAssistMetadata(),
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Parse the error message in the body to pick the fix: invalid token -> re-exchange/refresh; scope -> add scopes and re-authorize; quota -> back off and retry
- Always fetch userinfo immediately after a successful token exchange
- Store and honor the token's expires_in so you refresh before use
Defensive patterns
Strategy: try-catch
Try / catch
if strings.Contains(err.Error(), "userinfo: request failed") {
switch {
case strings.Contains(err.Error(), "Invalid Credentials"): // refresh token
case strings.Contains(err.Error(), "403"): // scope missing — re-authorize
}
} Prevention
- Parse the body message to choose refresh vs re-authorize
- Include email scope in the authorization request
When it happens
Trigger: 401 Invalid Credentials from an expired/revoked token; 403 with a scope message when the email scope was not granted; 429 quota messages.
Common situations: Reusing persisted tokens past expiry; authorization request missing the email scope; multiple OAuth clients sharing stored tokens.
Related errors
- antigravity token exchange: request failed: status %d: %s
- antigravity token exchange: request failed: status %d
- antigravity userinfo: request failed: status %d
- 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/2b2da4396b837e14.
Report an issue: GitHub.