eyaltoledano/claude-task-master · error · AuthenticationError
CODE_EXCHANGE_FAILED
CODE_EXCHANGE_FAILED
Error message
Failed to exchange code: ${error.message} What it means
exchangeCodeForSession throws AuthenticationError with code CODE_EXCHANGE_FAILED when the Supabase auth client's exchangeCodeForSession(call) returns an error while converting the OAuth authorization code into a session. The Supabase error message is embedded.
Source
Thrown at packages/tm-core/src/modules/integration/clients/supabase-client.ts:191
throw new AuthenticationError(
`Failed to start PKCE flow: ${(error as Error).message}`,
'PKCE_FAILED'
);
}
}
/**
* Exchange authorization code for session (PKCE flow)
*/
async exchangeCodeForSession(code: string): Promise<Session> {
const client = this.getClient();
try {
const { data, error } = await client.auth.exchangeCodeForSession(code);
if (error) {
throw new AuthenticationError(
`Failed to exchange code: ${error.message}`,
'CODE_EXCHANGE_FAILED'
);
}
if (!data?.session) {
throw new AuthenticationError(
'No session returned from code exchange',
'INVALID_RESPONSE'
);
}
this.logger.info('Successfully exchanged code for session');
return data.session;
} catch (error) {
if (error instanceof AuthenticationError) {
throw error;
}View on GitHub (pinned to c0c98d367c)
Solutions
- Restart the full signInWithPKCE flow to get a fresh code instead of reusing the old one
- Avoid re-running exchange on page refresh; mark the code as consumed after first exchange
- Verify the callback URL is captured fully and the code_verifier matches the one used at initiation
- Check clock synchronization if using the machine in a constrained environment
Example fix
// before
await client.exchangeCodeForSession(savedCode); // stale code
// after
const { url } = await client.signInWithPKCE(); // fresh flow
// exchange only the new code from this callback Defensive patterns
Strategy: retry
Validate before calling
if (!code || code.length < 10) {
// reject obviously malformed callback codes before exchanging
} Type guard
function hasUsableCode(cb: { code?: string | null }): cb is { code: string } {
return typeof cb.code === 'string' && cb.code.length > 0;
} Try / catch
try {
await client.exchangeCodeForSession(code);
} catch (e) {
if (e instanceof AuthenticationError && e.code === 'CODE_EXCHANGE_FAILED') {
await client.signInWithPKCE(); // restart flow: codes are single-use
}
} Prevention
- Never re-exchange a consumed code (guard against callback page refreshes)
- Mark codes as consumed immediately after a successful exchange
- Restart the full PKCE flow rather than retrying exchange with the same code
When it happens
Trigger: Calling exchangeCodeForSession(code) with a code that Supabase rejects: expired code, already-used code (PKCE codes are single-use), code from a mismatched code_verifier, or a malformed callback code.
Common situations: User refreshing the callback page (replays a consumed code), callback URL truncation cutting the code, clock skew invalidating the code, or rerunning the auth flow and exchanging a stale code.
Related errors
- PKCE_INIT_FAILED
- No refresh token received from server - session refresh will
- INVALID_RESPONSE
- PKCE_FAILED
- START_FLOW_FAILED
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/cbd4f742819cf5d7.
Report an issue: GitHub.