{"record":{"id":"64642581e63b658e","repo":"router-for-me/CLIProxyAPI","slug":"token-refresh-request-failed-w-646425","errorCode":null,"errorMessage":"token refresh request failed: %w","messagePattern":"token refresh request failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/codex/openai_auth.go","lineNumber":231,"sourceCode":"func (o *CodexAuth) refreshTokensSingleFlight(ctx context.Context, refreshToken string) (*CodexTokenData, error) {\n\tdata := url.Values{\n\t\t\"client_id\":     {ClientID},\n\t\t\"grant_type\":    {\"refresh_token\"},\n\t\t\"refresh_token\": {refreshToken},\n\t\t\"scope\":         {\"openid profile email\"},\n\t}\n\n\treq, errReq := http.NewRequestWithContext(ctx, \"POST\", TokenURL, strings.NewReader(data.Encode()))\n\tif errReq != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create refresh request: %w\", errReq)\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\treq.Header.Set(\"Accept\", \"application/json\")\n\n\tresp, errDo := o.httpClient.Do(req)\n\tif errDo != nil {\n\t\treturn nil, fmt.Errorf(\"token refresh request failed: %w\", errDo)\n\t}\n\tdefer func() {\n\t\tif errClose := resp.Body.Close(); errClose != nil {\n\t\t\tlog.Errorf(\"token refresh response body close error: %v\", errClose)\n\t\t}\n\t}()\n\n\tbody, errRead := io.ReadAll(resp.Body)\n\tif errRead != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read refresh response: %w\", errRead)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"token refresh failed with status %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\tvar tokenResp struct {\n\t\tAccessToken  string `json:\"access_token\"`","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/codex/openai_auth.go#L213-L249","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"td, err := auth.RefreshTokensWithRetry(ctx, rt, 3)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) {\n        // transport-level: schedule a later refresh instead of failing the credential\n        log.Warnf(\"transient refresh network error: %v\", err)\n    }\n}","preventionTips":["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."],"tags":["network","oauth","codex","token-refresh","proxy","transient"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}