router-for-me/CLIProxyAPI · error

token exchange request failed

Error message

token exchange request failed: %w

What it means

The HTTP round trip for the Codex token exchange (POST to TokenURL) failed at the transport level — DNS, TCP connect, TLS handshake, or mid-request disconnect. The request was built successfully; the error comes from httpClient.Do and is wrapped verbatim, so the underlying cause (dial tcp, x509, proxyconnect, etc.) is visible in the wrapped message.

Solutions

  1. Inspect the wrapped error text to identify the layer (DNS, TLS, proxy, reset) before changing anything.
  2. Test reachability: `curl -v <TokenURL>` from the same machine and user.
  3. If behind a TLS-intercepting proxy, trust its CA cert or set SSL_CERT_FILE/SSL_CERT_DIR.
  4. Fix or unset HTTP_PROXY/HTTPS_PROXY/NO_PROXY for the login process.
  5. Retry the login once network is confirmed working — transient resets are common.

Example fix

// before: default client, no proxy awareness
resp, err := o.httpClient.Do(req)

// after: ensure the client honors the environment and retries transport errors
transport := &http.Transport{ Proxy: http.ProxyFromEnvironment }
o.httpClient = &http.Client{ Transport: transport, Timeout: 30 * time.Second }
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm the token endpoint resolves and is reachable
if _, err := net.DialTimeout("tcp", "auth.openai.com:443", 5*time.Second); err != nil {
    return fmt.Errorf("token endpoint unreachable, fix network first: %w", err)
}

Try / catch

tok, err := auth.ExchangeCode(ctx, code)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) || strings.Contains(err.Error(), "dial") || strings.Contains(err.Error(), "proxy") {
        // transient transport failure: safe to restart the login flow later
        log.Warnf("network error during exchange: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: No internet or DNS failure resolving the OpenAI auth host; TLS interception by a corporate proxy with an untrusted CA; HTTP(S)_PROXY env var pointing at a dead proxy; connection reset by a firewall between the host and the token endpoint; context canceled while the request was in flight.

Common situations: Running login behind corporate proxy/VPN without configuring the proxy CA; egress firewall blocking the auth domain; flaky network during interactive login; HTTPS_PROXY misconfigured in the shell where cli-proxy-api runs.

Related errors


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

Appendix: source

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

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

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("token exchange failed with status %d: %s", resp.StatusCode, string(body))
	}

	// Parse token response
	var tokenResp struct {
		AccessToken  string `json:"access_token"`

View on GitHub (pinned to 78f0c4079e)