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
- Check the ctx passed into the exchange for prior cancellation (errors.Is(err, context.Canceled)).
- Pass a fresh, non-canceled context (context.Background() or one with an adequate timeout) for the login flow.
- 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
- Pass a fresh context.WithTimeout sized for the whole interactive login.
- Never reuse request-scoped contexts for multi-step OAuth flows.
- Handle SIGINT so shutdown does not cancel a login mid-exchange silently.
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
- port %d is already in use
- timeout waiting for OAuth callback
- token exchange request failed: %w
- failed to read token response: %w
- token exchange failed with status %d: %s
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/eaf000f00b9f1e4c.
Report an issue: GitHub.