router-for-me/CLIProxyAPI · error

antigravity token exchange: execute request: %w

Error message

antigravity token exchange: execute request: %w

What it means

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.

Source

Thrown at internal/auth/antigravity/auth.go:154

// ExchangeCodeForTokens exchanges authorization code for access and refresh tokens
func (o *AntigravityAuth) ExchangeCodeForTokens(ctx context.Context, code, redirectURI string) (*TokenResponse, error) {
	data := url.Values{}
	data.Set("code", code)
	data.Set("client_id", ClientID)
	data.Set("client_secret", ClientSecret)
	data.Set("redirect_uri", redirectURI)
	data.Set("grant_type", "authorization_code")

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, TokenEndpoint, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, fmt.Errorf("antigravity token exchange: create request: %w", err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, errDo := o.httpClient.Do(req)
	if errDo != nil {
		return nil, fmt.Errorf("antigravity token exchange: execute request: %w", errDo)
	}
	defer func() {
		if errClose := resp.Body.Close(); errClose != nil {
			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)
	}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Inspect the wrapped url.Error's Unwrap() to identify DNS vs TLS vs timeout
  2. Verify egress to the token endpoint (curl the TokenEndpoint URL) from the same environment
  3. If behind a MITM proxy, add its CA to the client's trust store or configure the proxy on httpClient
  4. Retry the exchange — OAuth code exchange is a one-shot operation, so retry quickly and note the code may expire
Defensive patterns

Strategy: retry

Try / catch

var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
	// retry once with a fresh code; code exchange is one-shot so get a new code if it was consumed
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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