{"record":{"id":"2970c92153e49bc7","repo":"router-for-me/CLIProxyAPI","slug":"antigravity-token-exchange-execute-request-w","errorCode":null,"errorMessage":"antigravity token exchange: execute request: %w","messagePattern":"antigravity token exchange: execute request: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/antigravity/auth.go","lineNumber":154,"sourceCode":"\n// ExchangeCodeForTokens exchanges authorization code for access and refresh tokens\nfunc (o *AntigravityAuth) ExchangeCodeForTokens(ctx context.Context, code, redirectURI string) (*TokenResponse, error) {\n\tdata := url.Values{}\n\tdata.Set(\"code\", code)\n\tdata.Set(\"client_id\", ClientID)\n\tdata.Set(\"client_secret\", ClientSecret)\n\tdata.Set(\"redirect_uri\", redirectURI)\n\tdata.Set(\"grant_type\", \"authorization_code\")\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, TokenEndpoint, strings.NewReader(data.Encode()))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"antigravity token exchange: create request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\tresp, errDo := o.httpClient.Do(req)\n\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}","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/antigravity/auth.go#L136-L172","documentation":"The Antigravity token exchange HTTP request was constructed but httpClient.Do failed. The wrapped error is typically *url.Error carrying the underlying cause: DNS failure, connection refused, TLS handshake error, timeout, or context cancellation.","triggerScenarios":"POST to the Google token endpoint fails due to no network, DNS resolution failure, corporate proxy blocking accounts.google.com, TLS interception with an untrusted CA, or the context deadline expiring mid-request.","commonSituations":"Running the OAuth flow in sandboxed CI without egress; self-signed MITM proxy not in the system trust store; transient network drop; firewall blocking Google OAuth endpoints.","solutions":["Inspect the wrapped url.Error's Unwrap() to identify DNS vs TLS vs timeout","Verify egress to the token endpoint (curl the TokenEndpoint URL) from the same environment","If behind a MITM proxy, add its CA to the client's trust store or configure the proxy on httpClient","Retry the exchange — OAuth code exchange is a one-shot operation, so retry quickly and note the code may expire"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var netErr net.Error\nif errors.As(err, &netErr) && netErr.Timeout() {\n\t// retry once with a fresh code; code exchange is one-shot so get a new code if it was consumed\n}","preventionTips":["Verify egress to Google OAuth endpoints before running the flow","Trust corporate proxy CAs in the http.Client","Set a generous but finite timeout on the exchange"],"tags":["oauth","antigravity","network","tls","proxy"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}