can1357/oh-my-pi · error · AIError.OAuthError
Failed to extract accountId from token
Error message
Failed to extract accountId from token
What it means
Thrown after a successful token exchange when the decoded/required fields are present but the ID/access token does not yield an accountId (no chatgpt account_id claim). The library needs the ChatGPT account identifier to construct Codex sessions, so a token without it is unusable and is rejected with kind='validation'.
Source
Thrown at packages/ai/src/registry/oauth/openai-codex.ts:212
`Token exchange failed: ${formatOpenAICodexTokenEndpointError(tokenResponse.status, bodyText)}`,
{ kind: "token-exchange", status: tokenResponse.status },
);
}
const tokenData = (await tokenResponse.json()) as {
access_token?: string;
refresh_token?: string;
id_token?: string;
expires_in?: number;
};
if (!tokenData.access_token || !tokenData.refresh_token || typeof tokenData.expires_in !== "number") {
throw new AIError.OAuthError("Token response missing required fields", { kind: "validation" });
}
const { accountId, email, planType } = getTokenProfile(tokenData.access_token, tokenData.id_token);
if (!accountId) {
throw new AIError.OAuthError("Failed to extract accountId from token", { kind: "validation" });
}
return {
access: tokenData.access_token,
refresh: tokenData.refresh_token,
expires: Date.now() + tokenData.expires_in * 1000,
accountId,
email,
orgId: accountId,
orgName: planType,
};
}
/**
* Login with OpenAI Codex OAuth
*/
export type OpenAICodexLoginOptions = OAuthController & {
/** Optional originator value for OpenAI Codex OAuth. Default matches OMP Codex request headers. */View on GitHub (pinned to 9690622007)
Solutions
- Ensure you log in with a ChatGPT account that has Codex/plus access, not an API-only account
- Update the CLI — newer versions track current OpenAI token claim shapes
- Try switching accounts at auth.openai.com and redoing the device login
- Inspect your access token's claims (jwt.io) to confirm whether chatgpt_account_id is present
Example fix
null
Defensive patterns
Strategy: validation
Validate before calling
// pre-check the account type you will authorize with: it must be a ChatGPT account
// with Codex access; API-only accounts lack chatgpt_account_id claims.
const claims = JSON.parse(Buffer.from(accessToken.split('.')[1], 'base64').toString());
if (!claims.chatgpt_account_id) throw new Error('Account has no ChatGPT account_id — use a ChatGPT-enabled account'); Type guard
function hasAccountId(d: { accountId?: string | null }): d is { accountId: string } {
return typeof d.accountId === 'string' && d.accountId.length > 0;
} Try / catch
try {
const tokens = await exchangeCodeForToken(code, verifier);
} catch (e) {
if (e instanceof AIError.OAuthError && e.message === 'Failed to extract accountId from token') {
console.error('Signed in with an account lacking ChatGPT/Codex claims. Re-login with a ChatGPT account.');
} else throw e;
} Prevention
- Log in with a ChatGPT account that has Codex access, not an API-only account
- Update the CLI when OpenAI changes JWT claim shapes
- Switch to the correct account at auth.openai.com before completing device login
- Decode your access token at jwt.io to verify chatgpt_account_id exists
When it happens
Trigger: getTokenProfile() parses the access token / id_token JWT claims and accountId comes back falsy — the token was issued without ChatGPT account claims (wrong auth audience, API-key-style token, non-ChatGPT OpenAI account type).
Common situations: Account is an org-only or API-only OpenAI account without a ChatGPT subscription; OpenAI changed the JWT claim shape and the CLI predates it; user authorized with a different account type than expected (e.g. team member without Codex access).
Related errors
- Token exchange failed: ${formatOpenAICodexTokenEndpointError
- Token response missing required fields
- Device authorization initiation failed: ${initResponse.statu
- Device authorization response missing required fields
- Device authorization cancelled
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b56c22132d1874f8.
Report an issue: GitHub.