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
- Read the wrapped cause — it distinguishes DNS vs TLS vs proxy vs canceled.
- Rely on the built-in retry (RefreshTokensWithRetry) — transient errors clear on the next attempt with backoff.
- Verify egress to the token host: `curl -v <TokenURL>` from the server host.
- Trust the corporate proxy CA (SSL_CERT_FILE) or fix proxy env vars and restart.
- 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
- Always use RefreshTokensWithRetry rather than a single-shot refresh.
- Monitor egress to the token endpoint from long-running servers.
- Keep proxy configuration stable for the process lifetime.
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
- failed to read refresh response: %w
- token exchange request failed: %w
- failed to read token response: %w
- failed to parse refresh response: %w
- token refresh failed after %d attempts: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/64642581e63b658e.
Report an issue: GitHub.