router-for-me/CLIProxyAPI · error
failed to create refresh request: %w
Error message
failed to create refresh request: %w
What it means
http.NewRequestWithContext failed while building the refresh-token POST in refreshTokensSingleFlight. Like the exchange path, method and TokenURL are hardcoded, so a failure here practically means the passed context is nil or already canceled — not a network problem. Distinguished from 207 by occurring before any socket is opened.
Source
Thrown at internal/auth/codex/openai_auth.go:223
}
tokenData, ok := result.(*CodexTokenData)
if !ok || tokenData == nil {
return nil, fmt.Errorf("token refresh failed: invalid single-flight result")
}
return tokenData, nil
}
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)View on GitHub (pinned to 78f0c4079e)
Solutions
- Check for prior context cancellation with errors.Is(err, context.Canceled) on the wrapped error.
- Give the refresh path its own short-lived context derived from Background, not one tied to request/shutdown lifetimes.
- If embedding via sdk/cliproxy, verify the context passed into token refresh calls is non-nil.
Example fix
// before ctx := requestCtx // canceled when the request is done _, _ = auth.RefreshTokensWithRetry(ctx, token, 3) // after refreshCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() _, _ = auth.RefreshTokensWithRetry(refreshCtx, token, 3)
Defensive patterns
Strategy: validation
Validate before calling
if ctx == nil || ctx.Err() != nil {
ctx = context.Background() // or return an explicit error
}
_, err := auth.RefreshTokens(ctx, refreshToken) Try / catch
td, err := auth.RefreshTokens(ctx, rt)
if err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
// request-building failure from a dead context; retry with a fresh one
}
} Prevention
- Derive refresh contexts from context.Background with their own timeout.
- Do not tie background refreshes to request or shutdown lifetimes.
When it happens
Trigger: Refresh attempted with a canceled context (shutdown in progress); nil context reaching this function through a custom integration; modified TokenURL constant.
Common situations: Config hot-reload or process shutdown canceling the parent context exactly as a background refresh fires; SDK embedders passing the wrong context into the refresh path.
Related errors
- failed to create token request: %w
- token refresh request failed: %w
- failed to read refresh response: %w
- token refresh failed with status %d: %s
- failed to parse refresh response: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/040551db952d7b2e.
Report an issue: GitHub.