router-for-me/CLIProxyAPI · error

failed to create token request: %w

Error message

failed to create token request: %w

What it means

Returned when http.NewRequestWithContext fails while building the POST to the Codex token endpoint (TokenURL) during the OAuth authorization-code exchange. NewRequestWithContext only errors on an invalid method, a malformed URL, or a nil context — since method and URL are hardcoded constants here, in practice this indicates a nil or canceled context rather than anything about the network.

Source

Thrown at internal/auth/codex/openai_auth.go:118

	if pkceCodes == nil {
		return nil, fmt.Errorf("PKCE codes are required for token exchange")
	}
	if strings.TrimSpace(redirectURI) == "" {
		return nil, fmt.Errorf("redirect URI is required for token exchange")
	}

	// Prepare token exchange request
	data := url.Values{
		"grant_type":    {"authorization_code"},
		"client_id":     {ClientID},
		"code":          {code},
		"redirect_uri":  {strings.TrimSpace(redirectURI)},
		"code_verifier": {pkceCodes.CodeVerifier},
	}

	req, err := http.NewRequestWithContext(ctx, "POST", TokenURL, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, fmt.Errorf("failed to create token request: %w", err)
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Accept", "application/json")

	resp, err := o.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("token exchange request failed: %w", err)
	}
	defer func() {
		_ = resp.Body.Close()
	}()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read token response: %w", err)
	}
	// log.Debugf("Token response: %s", string(body))

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Check the ctx passed into the exchange for prior cancellation (errors.Is(err, context.Canceled)).
  2. Pass a fresh, non-canceled context (context.Background() or one with an adequate timeout) for the login flow.
  3. If it persists, verify TokenURL in internal/auth/codex has not been modified locally.

Example fix

// before
ctx, cancel := context.WithCancel(context.Background())
cancel() // canceled too early
tok, err := auth.ExchangeCode(ctx, code)

// after
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
tok, err := auth.ExchangeCode(ctx, code)
Defensive patterns

Strategy: validation

Validate before calling

if ctx == nil || ctx.Err() != nil {
    return fmt.Errorf("exchange aborted before start: %w", ctx.Err())
}
tok, err := auth.ExchangeCode(ctx, code)

Try / catch

tok, err := auth.ExchangeCode(ctx, code)
if err != nil {
    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        // context problem, not provider problem: rebuild ctx and restart flow
    }
    return err
}

Prevention

When it happens

Trigger: Calling ExchangeCode with a context that is already canceled or expired; passing context.Background() that was canceled upstream by a signal handler; theoretically a corrupted TokenURL constant after local modifications.

Common situations: Ctrl+C or a shutdown signal cancels the parent context mid-login; a wrapper cancels the auth timeout context before the exchange step begins; almost never seen in normal operation because the URL and method are fixed.

Related errors


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