decolua/9router · warning
[Usage] ${connection.provider}: force refresh failed: ${retr
Error message
[Usage] ${connection.provider}: force refresh failed: ${retryError.message} What it means
Console.warn in the GET usage handler when the force-refresh retry path fails. If the provider usage call reports an expired OAuth token (isAuthExpiredMessage) and a refresh token exists, the route refreshes credentials and re-fetches usage; if the refresh or the retry usage fetch throws, this message is logged and the original stale `usage` object is returned in the JSON response.
Source
Thrown at src/app/api/usage/[connectionId]/route.js:182
console.error("[Usage API] Credential refresh failed:", refreshError);
return Response.json({
error: `Credential refresh failed: ${refreshError.message}`
}, { status: 401 });
}
}
// Fetch usage from provider API
let usage = await getUsageForProvider(connection, proxyOptions, { force });
// If provider returned an auth-expired message instead of throwing,
// force-refresh token and retry once (OAuth only)
if (isOAuth && isAuthExpiredMessage(usage) && connection.refreshToken) {
try {
const retryResult = await refreshAndUpdateCredentials(connection, true, proxyOptions);
connection = retryResult.connection;
usage = await getUsageForProvider(connection, proxyOptions, { force });
} catch (retryError) {
console.warn(`[Usage] ${connection.provider}: force refresh failed: ${retryError.message}`);
}
}
return Response.json(usage);
} catch (error) {
const provider = connection?.provider ?? "unknown";
console.warn(`[Usage] ${provider}: ${error.message}`);
return Response.json({ error: error.message }, { status: 500 });
}
}
View on GitHub (pinned to 90b52e06ff)
Solutions
- Re-authenticate the OAuth connection in the dashboard to obtain a fresh refresh token.
- Check the underlying retryError.message (e.g. invalid_grant vs ENOTFOUND) to distinguish credential death from network issues.
- Verify proxy settings and outbound connectivity to the provider's token/usage endpoints.
- Retry the GET; if it persists, disable/re-add the connection.
Example fix
// before
catch (retryError) {
console.warn(`[Usage] ${connection.provider}: force refresh failed: ${retryError.message}`);
}
// after
catch (retryError) {
console.warn(`[Usage] ${connection.provider}: force refresh failed: ${retryError.message}`);
usage = { ...usage, authError: retryError.message, needsReauth: retryError.message.includes("invalid_grant") };
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check connection health before querying usage
if (!conn.refreshToken) console.warn("No refresh token — usage may fail on expired access token"); Type guard
function isUsagePayload(u) { return u && typeof u === "object" && !u.error; } Try / catch
try {
const res = await fetch(`/api/usage/${connId}`);
const usage = await res.json();
if (usage?.needsReauth || usage?.authError) await reauthenticate(connId);
} catch (e) { /* handle fetch failure */ } Prevention
- Periodically refresh OAuth connections proactively instead of waiting for the expired-token path.
- Watch for repeated force-refresh warnings per provider; treat them as signals to re-add the account.
- Verify proxy/firewall rules allow the host to reach each provider's token endpoint.
- Alert on usage responses that consistently come back stale.
When it happens
Trigger: GET /api/usage/[connectionId] on an OAuth provider where the usage response indicates an expired token, and refreshAndUpdateCredentials throws (revoked refresh token, token endpoint unreachable, bad proxy) or getUsageForProvider throws on the retry (network error).
Common situations: Accounts idle past the refresh token lifetime; upstream provider OAuth endpoint outage; proxy misconfiguration; expired/revoked refresh tokens after password change or app deauthorization at the provider.
Related errors
- [Codex Reset Credits] force refresh failed: ${retryError.mes
- [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/d9a5de3f4cfd1d7d.
Report an issue: GitHub.