{"record":{"id":"e5b126e95a7a1388","repo":"router-for-me/CLIProxyAPI","slug":"antigravity-token-exchange-request-failed-status-e5b126","errorCode":null,"errorMessage":"antigravity token exchange: request failed: status %d: %s","messagePattern":"antigravity token exchange: request failed: status (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/antigravity/auth.go","lineNumber":171,"sourceCode":"\tif errDo != nil {\n\t\treturn nil, fmt.Errorf(\"antigravity token exchange: execute request: %w\", errDo)\n\t}\n\tdefer func() {\n\t\tif errClose := resp.Body.Close(); errClose != nil {\n\t\t\tlog.Errorf(\"antigravity token exchange: close body error: %v\", errClose)\n\t\t}\n\t}()\n\n\tif resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {\n\t\tbodyBytes, errRead := io.ReadAll(io.LimitReader(resp.Body, 8<<10))\n\t\tif errRead != nil {\n\t\t\treturn nil, fmt.Errorf(\"antigravity token exchange: read response: %w\", errRead)\n\t\t}\n\t\tbody := strings.TrimSpace(string(bodyBytes))\n\t\tif body == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"antigravity token exchange: request failed: status %d\", resp.StatusCode)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"antigravity token exchange: request failed: status %d: %s\", resp.StatusCode, body)\n\t}\n\n\tvar token TokenResponse\n\tif errDecode := json.NewDecoder(resp.Body).Decode(&token); errDecode != nil {\n\t\treturn nil, fmt.Errorf(\"antigravity token exchange: decode response: %w\", errDecode)\n\t}\n\treturn &token, nil\n}\n\n// FetchUserInfo retrieves user email from Google\nfunc (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) {\n\taccessToken = strings.TrimSpace(accessToken)\n\tif accessToken == \"\" {\n\t\treturn \"\", fmt.Errorf(\"antigravity userinfo: missing access token\")\n\t}\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"antigravity userinfo: create request: %w\", err)","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/antigravity/auth.go#L153-L189","documentation":"The Antigravity token exchange endpoint returned a non-2xx status and the body (up to 8 KiB) is included verbatim. Google OAuth errors are JSON like {\"error\":\"invalid_grant\",\"error_description\":\"...\"}; the body tells you the exact protocol failure.","triggerScenarios":"invalid_grant (expired/used code, clock skew), invalid_client (bad client secret), redirect_uri_mismatch, unauthorized_client — each surfaces as 400/401 with a JSON error body.","commonSituations":"Replaying a used auth code during debugging; expired refresh-token flow bugs; misconfigured OAuth client credentials in a forked build.","solutions":["Read the error/error_description fields in the body: invalid_grant means restart the flow with a fresh code; invalid_client means fix credentials; redirect_uri_mismatch means align the redirect URI","For clock-skew-induced invalid_grant, sync system time (NTP)","Ensure the code is exchanged exactly once, immediately after the callback"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"token exchange: request failed\") {\n\tswitch {\n\tcase strings.Contains(err.Error(), \"invalid_grant\"): // fresh code needed\n\tcase strings.Contains(err.Error(), \"invalid_client\"): // fix credentials\n\tcase strings.Contains(err.Error(), \"redirect_uri_mismatch\"): // align redirect\n\t}\n}","preventionTips":["Read error/error_description from the body to route the fix","Keep client credentials in sync with the registered OAuth app","Sync system clock (NTP) to avoid invalid_grant from skew"],"tags":["oauth","antigravity","http-status","error-body"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}