mastra-ai/mastra · error
Token exchange failed
Error message
Token exchange failed
What it means
Thrown by the OpenAI Codex OAuth login flow after the user authorizes in the browser and the callback delivers an authorization code. The library called the OAuth token endpoint with exchangeAuthorizationCode and got a non-success result, so it refuses to produce credentials. This means the code-for-token swap at the provider failed (bad code, bad verifier, or provider-side rejection).
Source
Thrown at mastracode/sdk/src/auth/providers/openai-codex.ts:691
// Fallback to onPrompt if still no code
if (!code) {
const input = await options.onPrompt({
message: 'Paste the authorization code (or full redirect URL):',
});
const parsed = parseAuthorizationInput(input);
if (parsed.state && parsed.state !== state) {
throw new Error('State mismatch');
}
code = parsed.code;
}
if (!code) {
throw new Error('Missing authorization code');
}
const tokenResult = await exchangeAuthorizationCode(code, verifier, server.redirectUri);
if (tokenResult.type !== 'success') {
throw new Error('Token exchange failed');
}
const accountId = requireAccountId(tokenResult);
return {
access: tokenResult.access,
refresh: tokenResult.refresh,
expires: tokenResult.expires,
accountId,
};
} finally {
server.close();
}
}
export const __testing = {
createAuthorizationFlow,
decodeJwt,View on GitHub (pinned to 75dd419e61)
Solutions
- Restart the login flow from scratch so a fresh authorization code and matching PKCE verifier are used.
- Verify the redirect_uri registered for the OpenAI Codex OAuth app exactly matches the one the local server listens on.
- Complete the browser authorization promptly; authorization codes expire in minutes.
- Check https://status.openai.com / provider logs for token-endpoint incidents; retry later.
Example fix
// before: re-running a stale login attempt with an old callback URL
const code = staleCallbackUrl.searchParams.get('code');
await sdk.auth.login('openai-codex', callbacks); // Token exchange failed
// after: start a clean login and finish it in one session
await sdk.auth.login('openai-codex', callbacks); // complete browser auth immediately Defensive patterns
Strategy: try-catch
Validate before calling
// before login: ensure no stale in-flight login and app config is sane
if (!openaiAppRedirectUri.startsWith('http://127.0.0.1') && !openaiAppRedirectUri.startsWith('https://')) {
throw new Error('Configure a valid redirect URI registered with the OpenAI app');
} Type guard
function isTokenExchangeSuccess(r: { type: string }): r is { type: 'success'; access: string } {
return r.type === 'success';
} Try / catch
try {
await sdk.auth.login('openai-codex', callbacks);
} catch (e) {
if (e instanceof Error && e.message === 'Token exchange failed') {
// discard the code/verifier and restart the login flow cleanly
await sdk.auth.login('openai-codex', callbacks);
}
} Prevention
- Always complete the browser authorization in the same session that started it
- Keep the redirect URI identical to the one registered in the OpenAI app
- Never reuse authorization codes; codes are single-use and expire in minutes
- Retry transient failures once, then restart the full flow
When it happens
Trigger: Calling login() for the openai-codex provider when exchangeAuthorizationCode(code, verifier, server.redirectUri) returns a result whose type !== 'success' — e.g. the provider returned an OAuth error response instead of tokens.
Common situations: The redirect URI registered in the OpenAI app does not match the one used by the local callback server; the user reuses an old/expired authorization code (codes are single-use and short-lived); PKCE verifier/session mismatch from restarting login mid-flow; clock skew or provider outage.
Related errors
- GitHub OAuth token exchange returned no token: ${data.error_
- Linear capabilities require an OAuth connection.
- Failed to refresh OpenAI Codex token
- AZURE_AD_TOKEN_ERROR
- ${validationResult.error || 'invalid_token'}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/443c600fa58d5c75.
Report an issue: GitHub.