decolua/9router · warning
[Codex Reset Credits] force refresh failed: ${retryError.mes
Error message
[Codex Reset Credits] force refresh failed: ${retryError.message} What it means
Not a thrown error but a console.warn logged in the POST handler of the Codex reset-credits route when the OAuth recovery path fails. After a rate-limit-reset credit consumption returns an auth-expired result, the route force-refreshes the OAuth tokens via refreshAndUpdateCredentials and retries consumption; if the refresh or the retry consumption throws, the catch logs this message and falls through to getResponseForConsumeResult with the original failed consumeResult.
Source
Thrown at src/app/api/usage/[connectionId]/codex-reset-credits/route.js:146
const { isOAuth, proxyOptions } = resolved;
if (isOAuth) {
const refreshed = await refreshCodexConnection(connection, proxyOptions);
if (refreshed.response) return refreshed.response;
connection = refreshed.connection;
}
// Server-generated redeem id prevents client-controlled replay
const redeemRequestId = crypto.randomUUID();
let consumeResult = await consumeCodexRateLimitResetCredit(connection.accessToken, redeemRequestId, proxyOptions);
if (isOAuth && isAuthExpiredResult(consumeResult) && connection.refreshToken) {
try {
const retryResult = await refreshAndUpdateCredentials(connection, true, proxyOptions);
connection = retryResult.connection;
consumeResult = await consumeCodexRateLimitResetCredit(connection.accessToken, redeemRequestId, proxyOptions);
} catch (retryError) {
console.warn(`[Codex Reset Credits] force refresh failed: ${retryError.message}`);
}
}
return getResponseForConsumeResult(consumeResult, redeemRequestId);
} catch (error) {
const provider = connection?.provider ?? "unknown";
console.warn(`[Codex Reset Credits] ${provider}: ${error.message}`);
return Response.json({ error: error.message }, { status: 500 });
}
}
View on GitHub (pinned to 90b52e06ff)
Solutions
- Re-authenticate the Codex connection: delete and re-add the OAuth account so a fresh refresh token is stored.
- Check proxy/network reachability of the OAuth token endpoint and the Codex API from the host, including proxyOptions configuration.
- Inspect the logged retryError.message for the underlying cause (e.g. 'invalid_grant' means the refresh token is dead).
- Retry the request after confirming credentials; ensure only one instance uses the account to avoid token rotation races.
Example fix
// before
try {
const retryResult = await refreshAndUpdateCredentials(connection, true, proxyOptions);
connection = retryResult.connection;
consumeResult = await consumeCodexRateLimitResetCredit(connection.accessToken, redeemRequestId, proxyOptions);
} catch (retryError) {
console.warn(`[Codex Reset Credits] force refresh failed: ${retryError.message}`);
}
// after
try {
const retryResult = await refreshAndUpdateCredentials(connection, true, proxyOptions);
connection = retryResult.connection;
consumeResult = await consumeCodexRateLimitResetCredit(connection.accessToken, redeemRequestId, proxyOptions);
} catch (retryError) {
console.warn(`[Codex Reset Credits] force refresh failed: ${retryError.message}`);
if (retryError.message.includes("invalid_grant")) {
await markConnectionNeedsReauth(connection.id); // surface re-auth to dashboard
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling the reset-credits endpoint, verify the connection still has a refresh token
function canRetryOAuth(conn) { return Boolean(conn?.refreshToken); } Type guard
function hasRefreshToken(conn) { return typeof conn?.refreshToken === "string" && conn.refreshToken.length > 0; } Try / catch
try {
const res = await fetch(`/api/usage/${connId}/codex-reset-credits`, { method: "POST" });
const body = await res.json();
if (!res.ok || body.error) {
if (/invalid_grant|refresh/i.test(body.error)) await reauthenticate(connId);
}
} catch (e) { /* network error — retry with backoff */ } Prevention
- Re-authenticate Codex OAuth connections before refresh tokens expire from long idle periods.
- Run only one app instance per OAuth account to avoid refresh-token rotation races.
- Monitor logs for repeated 'force refresh failed' lines on the same connection — that signals a dead refresh token.
- Ensure the proxy configuration allows outbound access to the provider token endpoint.
When it happens
Trigger: POST to /api/usage/[connectionId]/codex-reset-credits on an OAuth Codex connection where (a) the access token is expired (isAuthExpiredResult matched), (b) refreshAndUpdateCredentials throws (invalid/revoked refresh token, network failure to the OAuth token endpoint, proxy error), or (c) the retried consumeCodexRateLimitResetCredit call throws (network error to Codex upstream).
Common situations: Expired or revoked refresh tokens on long-idle Codex OAuth accounts; corporate proxy blocking the token endpoint; transient network outage during the retry; refresh token rotated elsewhere (multiple instances sharing one account).
Related errors
- [Usage] ${connection.provider}: force refresh failed: ${retr
- [AutoPing] ${provider}:${conn.id}: refresh failed: ${e.messa
- loadCodeAssist failed: HTTP ${response.status} ${errorText.s
- onboardUser HTTP ${response.status}: ${errorText.slice(0, 20
- Zed did not return an LLM token
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/fe897a33e259ab9f.
Report an issue: GitHub.