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

  1. 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
  2. Always fetch userinfo immediately after a successful token exchange
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/2b2da4396b837e14. Report an issue: GitHub.