coleam00/Archon · error
Stored OpenAI credential has no refresh token.
Error message
Stored OpenAI credential has no refresh token.
What it means
refreshOpenAiOAuthCredentials reads the refresh token from the stored credential before contacting OpenAI. If the stored OAuthCredentials has no string `refresh` field, it throws immediately instead of sending a doomed request — a credential without a refresh token can never be refreshed and must be re-created via a fresh login.
Source
Thrown at packages/core/src/credentials/openai-oauth.ts:299
}),
'exchange',
signal
);
return credentialsFromTokenResponse(json, 'exchange');
}
/**
* Refresh an OpenAI subscription credential directly (same public client id).
* Preserves `id_token` (and `refresh`) when the refresh response omits them —
* the reason this does NOT go through Pi's `getOAuthApiKey`, which would
* rebuild the blob from scratch and drop the id_token on every rotation.
*/
export async function refreshOpenAiOAuthCredentials(
creds: OAuthCredentials
): Promise<OpenAiOAuthCredentials> {
const refresh = typeof creds.refresh === 'string' ? creds.refresh : '';
if (!refresh) {
throw new Error('Stored OpenAI credential has no refresh token.');
}
const json = await postTokenRequest(
new URLSearchParams({
grant_type: 'refresh_token',
client_id: OPENAI_CLIENT_ID,
refresh_token: refresh,
}),
'refresh'
);
return credentialsFromTokenResponse(json, 'refresh', creds);
}
/**
* Mint a usable bearer from a stored OpenAI credential blob, refreshing first
* when expired. Same contract as Pi's `getOAuthApiKey` (`{ newCredentials,
* apiKey } | null`) so the store's shared rotation/resave logic applies
* unchanged. Throws when a needed refresh fails.
*View on GitHub (pinned to 0773b97458)
Solutions
- Force a fresh OAuth login (authorization-code + PKCE) to obtain a new credential with a refresh token.
- Inspect the stored credential row/JSON to confirm the refresh field is present and non-empty; re-import if truncated.
- Check the code path that saved the credential — earlier versions or error paths may have omitted refresh_token.
- If the credential was migrated, backfill the refresh token from the original login response or re-authenticate.
Example fix
// before
const fresh = await refreshOpenAiOAuthCredentials({ access: token }); // throws: no refresh
// after: guard and re-authenticate when refresh is absent
if (typeof creds.refresh !== 'string' || !creds.refresh) {
creds = await runOpenAiLoginFlow();
}
const fresh = await refreshOpenAiOAuthCredentials(creds); Defensive patterns
Strategy: type-guard
Validate before calling
function canRefresh(c) { return c && typeof c.refresh === 'string' && c.refresh.length > 0; }
if (!canRefresh(creds)) throw new Error('stored OpenAI credential lacks refresh token; re-authentication required'); Type guard
function isOpenAiRefreshable(c: OAuthCredentials): c is OAuthCredentials & { refresh: string } {
return typeof c.refresh === 'string' && c.refresh.length > 0;
} Try / catch
try {
return await refreshOpenAiOAuthCredentials(creds);
} catch (e) {
if (e.message === 'Stored OpenAI credential has no refresh token.') {
return await promptFreshOpenAiLogin(); // user-visible re-auth
}
throw e;
} Prevention
- Validate stored credentials at load time: fail fast if refresh is missing so re-auth happens early, not mid-run.
- Never write credential rows without refresh_token; enforce at the persistence boundary.
- Include refresh in credential export/import/backup formats.
- Re-authenticate proactively before long operations if the credential predates refresh-token storage.
When it happens
Trigger: Calling refreshOpenAiOAuthCredentials (directly or via next()/mintOpenAiOAuthApiKey) with a credential whose `refresh` property is undefined, non-string, or empty.
Common situations: Credential loaded from an old database row created before refresh tokens were stored; credentials constructed by hand from just an access token; partial deserialization of stored JSON that dropped the refresh field.
Related errors
- OpenAI token ${operation} response missing refresh_token.
- OpenAI token ${operation} response missing access_token/expi
- OpenAI token ${operation} response did not include an id_tok
- Failed to extract the ChatGPT account id from the OpenAI acc
- OAuth state mismatch.
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/13f9b7c6da00beec.
Report an issue: GitHub.