can1357/oh-my-pi · error · AIError.OAuthError
OAuth refresh did not produce a usable credential for provid
Error message
OAuth refresh did not produce a usable credential for provider: ${provider} What it means
Thrown as AIError.OAuthError with kind 'token-refresh' when an OAuth token refresh completes but does not yield a usable credential (and it is not a reload of an already-refreshed credential). The library treats this as a definitive refresh failure for the provider so the retry layer can stop replaying the failed token.
Source
Thrown at packages/ai/src/auth-storage.ts:5255
),
isDefinitiveFailure: error => AIError.isDefinitiveOAuthFailure(String(error)),
disabledCause: error => `oauth refresh failed: ${String(error)}`,
});
if (result.credential) {
if (result.refreshed) {
// We performed this refresh ourselves — trust the provider's new token
// even when its lifetime is shorter than the refresh skew (some grants
// are legitimately short-lived); the next resolve simply treats it as
// due for refresh again instead of rejecting a token we just minted.
if (Date.now() < result.credential.expires) return result.credential;
} else if (Date.now() + OAUTH_REFRESH_SKEW_MS < result.credential.expires) {
// Reloaded (not refreshed by us) credential — match #refreshOAuthCredential's
// freshness contract: a reload within the refresh skew still counts as
// needing refresh, so returning it here would make the final candidate pass
// refresh the same row again and replay the token we just failed on.
return result.credential;
}
throw new AIError.OAuthError(
`OAuth refresh did not produce a usable credential for provider: ${provider}`,
{
kind: "token-refresh",
provider,
},
);
}
throw new AIError.OAuthError(`OAuth credential no longer exists for provider: ${provider}`, {
kind: "token-refresh",
provider,
});
}
return this.#requestOAuthCredentialRefresh(provider, credential, credentialId, signal);
}
async #requestOAuthCredentialRefresh(
provider: Provider,
credential: OAuthCredential,View on GitHub (pinned to 9690622007)
Solutions
- Re-run the full OAuth login flow for the provider to obtain a new refresh token
- Check the provider account status — revoked apps/sessions produce empty refresh results
- Inspect provider API responses/logs for why the refresh returned no token
- Retry the request; withOAuthAccess treats kind 'token-refresh' as a replay-then-stop signal, so re-authentication is the real fix
Example fix
// before
const access = await withOAuthAccess(storage, "codex", call); // OAuthError token-refresh
// after
try {
return await withOAuthAccess(storage, "codex", call);
} catch (error) {
if (error instanceof AIError.OAuthError && error.kind === "token-refresh") {
await reLogin(provider); // refresh token is dead; get a new one
return withOAuthAccess(storage, "codex", call);
}
throw error;
} Defensive patterns
Strategy: try-catch
Type guard
function isTokenRefreshError(e: unknown): e is AIError.OAuthError {
return e instanceof AIError.OAuthError && e.kind === "token-refresh";
} Try / catch
try {
return await withOAuthAccess(storage, provider, attempt);
} catch (error) {
if (isTokenRefreshError(error)) {
await reLogin(provider); // refresh produced nothing usable
return withOAuthAccess(storage, provider, attempt);
}
throw error;
} Prevention
- Re-authenticate proactively when refresh tokens approach provider expiry windows
- Handle kind "token-refresh" OAuthErrors as 're-login required', never as retryable
- Monitor provider account/consent revocation events
When it happens
Trigger: A refresh attempt (or reload path) returns a result whose credential is undefined/unusable — e.g. the refresh succeeded server-side but produced no storable credential, or the row was removed mid-refresh so no candidate remains.
Common situations: Provider revoked the refresh token or the account (refresh returns empty); refresh endpoint returns 200 with a malformed/absent token payload; concurrent logout removing the credential between refresh start and finish.
Related errors
- OAuth credential no longer exists for provider: ${provider}
- OAuth provider "${provider}" does not support token refresh
- Antigravity credentials missing projectId
- Google Cloud credentials missing projectId
- GitLab Duo Workflow OAuth refresh failed: ${response.status}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/68d9f252f1feb06b.
Report an issue: GitHub.