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

  1. Restart the full signInWithPKCE flow to get a fresh code instead of reusing the old one
  2. Avoid re-running exchange on page refresh; mark the code as consumed after first exchange
  3. Verify the callback URL is captured fully and the code_verifier matches the one used at initiation
  4. 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

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


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/cbd4f742819cf5d7. Report an issue: GitHub.