router-for-me/CLIProxyAPI · error

antigravity token exchange: create request: %w

Error message

antigravity token exchange: create request: %w

What it means

The Antigravity OAuth token exchange failed at request construction: http.NewRequestWithContext rejected the inputs. With a fixed POST this almost always means the TokenEndpoint URL constant is malformed, or the context is already cancelled (Go 1.20+ reports an invalid context at NewRequest time).

Source

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

	params.Set("redirect_uri", redirectURI)
	params.Set("response_type", "code")
	params.Set("scope", strings.Join(Scopes, " "))
	params.Set("state", state)
	return AuthEndpoint + "?" + params.Encode()
}

// 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)
		}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Check whether the ctx passed to ExchangeCodeForTokens derives from an already-finished HTTP request; use a fresh context.Background() with a timeout for the exchange
  2. Verify TokenEndpoint is a valid absolute URL
  3. Update Go version to get clearer context-related error messages if on an old release

Example fix

// before
ctx := r.Context() // callback request context, may be cancelled
tokens, err := auth.ExchangeCodeForTokens(ctx, code, redirect)

// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
tokens, err := auth.ExchangeCodeForTokens(ctx, code, redirect)
Defensive patterns

Strategy: validation

Validate before calling

if ctx.Err() != nil {
	return ctx.Err()
}
tokens, err := auth.ExchangeCodeForTokens(ctx, code, redirect)

Try / catch

if _, err := auth.ExchangeCodeForTokens(ctx, code, redirect); err != nil {
	if strings.Contains(err.Error(), "create request") {
		// context or endpoint problem — restart flow with fresh context
	}
}

Prevention

When it happens

Trigger: Building the POST to TokenEndpoint with a nil or already-cancelled/expired context; TokenEndpoint constant corrupted (spaces, bad scheme) via code change or build flags.

Common situations: OAuth callback handler passing a request context that was cancelled when the callback request disconnected; upstream constant change in a fork.

Related errors


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