router-for-me/CLIProxyAPI · error

token refresh request failed: %w

Error message

token refresh request failed: %w

What it means

The HTTP round trip for the token refresh POST failed at the transport layer (DNS/TCP/TLS/reset), wrapped from httpClient.Do. Because refresh runs in the background (often via RefreshTokensWithRetry with singleflight), this error surfaces during normal proxy operation, not just login. The wrapped message names the actual transport cause.

Source

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

func (o *CodexAuth) refreshTokensSingleFlight(ctx context.Context, refreshToken string) (*CodexTokenData, error) {
	data := url.Values{
		"client_id":     {ClientID},
		"grant_type":    {"refresh_token"},
		"refresh_token": {refreshToken},
		"scope":         {"openid profile email"},
	}

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

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

	resp, errDo := o.httpClient.Do(req)
	if errDo != nil {
		return nil, fmt.Errorf("token refresh request failed: %w", errDo)
	}
	defer func() {
		if errClose := resp.Body.Close(); errClose != nil {
			log.Errorf("token refresh response body close error: %v", errClose)
		}
	}()

	body, errRead := io.ReadAll(resp.Body)
	if errRead != nil {
		return nil, fmt.Errorf("failed to read refresh response: %w", errRead)
	}

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

	var tokenResp struct {
		AccessToken  string `json:"access_token"`

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Read the wrapped cause — it distinguishes DNS vs TLS vs proxy vs canceled.
  2. Rely on the built-in retry (RefreshTokensWithRetry) — transient errors clear on the next attempt with backoff.
  3. Verify egress to the token host: `curl -v <TokenURL>` from the server host.
  4. Trust the corporate proxy CA (SSL_CERT_FILE) or fix proxy env vars and restart.
  5. If errors persist after network is restored, force a refresh or restart the process to re-arm the scheduler.
Defensive patterns

Strategy: retry

Try / catch

td, err := auth.RefreshTokensWithRetry(ctx, rt, 3)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) {
        // transport-level: schedule a later refresh instead of failing the credential
        log.Warnf("transient refresh network error: %v", err)
    }
}

Prevention

When it happens

Trigger: Transient DNS failure when a stored credential auto-refreshes; egress firewall blocking the auth host mid-session; proxy env changes after startup; TLS certificate pinning/interception breaking the handshake; context deadline hit during the refresh request.

Common situations: Long-running server losing network (laptop sleep/resume); corporate proxy CA not trusted; refresh storm during provider incident; VPN route changes after the process started.

Related errors


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