{"record":{"id":"f3a30d2a11d8a217","repo":"eyaltoledano/claude-task-master","slug":"mfa-verification-failed-f3a30d","errorCode":"MFA_VERIFICATION_FAILED","errorMessage":"Failed to create MFA challenge: ${challengeError?.message || 'Unknown error'}","messagePattern":"Failed to create MFA challenge: (.+?)","errorType":"error_code","errorClass":"AuthenticationError","httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/modules/integration/clients/supabase-client.ts","lineNumber":552,"sourceCode":"\t\t\treturn { required: false };\n\t\t}\n\t}\n\n\t/**\n\t * Verify MFA code and upgrade session to AAL2\n\t */\n\tasync verifyMFA(factorId: string, code: string): Promise<Session> {\n\t\tconst client = this.getClient();\n\n\t\ttry {\n\t\t\tthis.logger.info('Verifying MFA code...');\n\n\t\t\t// Create MFA challenge\n\t\t\tconst { data: challengeData, error: challengeError } =\n\t\t\t\tawait client.auth.mfa.challenge({ factorId });\n\n\t\t\tif (challengeError || !challengeData) {\n\t\t\t\tthrow new AuthenticationError(\n\t\t\t\t\t`Failed to create MFA challenge: ${challengeError?.message || 'Unknown error'}`,\n\t\t\t\t\t'MFA_VERIFICATION_FAILED'\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Verify the TOTP code\n\t\t\tconst { data, error } = await client.auth.mfa.verify({\n\t\t\t\tfactorId,\n\t\t\t\tchallengeId: challengeData.id,\n\t\t\t\tcode\n\t\t\t});\n\n\t\t\tif (error) {\n\t\t\t\tthis.logger.error('MFA verification failed:', error);\n\t\t\t\tthrow new AuthenticationError(\n\t\t\t\t\t`Invalid MFA code: ${error.message}`,\n\t\t\t\t\t'INVALID_MFA_CODE'\n\t\t\t\t);","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/integration/clients/supabase-client.ts#L534-L570","documentation":"SupabaseClient.verifyMFA() throws this when `client.auth.mfa.challenge({factorId})` returns an error or no challenge data. Before a TOTP code can be verified, a challenge must be created for the factor; if that fails, verification cannot proceed. Code: MFA_VERIFICATION_FAILED.","triggerScenarios":"Calling verifyMFA with an invalid/unverified factorId, a factor that was deleted or unenrolled, an AAL1 session that is expired (challenge requires an authenticated session), or a Supabase-side MFA error (rate limiting, 404 factor not found).","commonSituations":"User unenrolled TOTP after the CLI cached the factorId; passing a factorId from a different user/session; MFA disabled at project level; session expired between login and MFA prompt; requesting challenges too frequently and hitting rate limits.","solutions":["Re-run checkMFARequired() to get a fresh, verified factorId before calling verifyMFA.","Ensure a valid AAL1 session exists (getSession() returns a session) before starting the MFA challenge.","Have the user confirm the TOTP factor is still enrolled and verified in their account settings.","Wait briefly and retry if rate-limited; otherwise check Supabase Auth logs for the challenge failure reason."],"exampleFix":"// before\nconst mfa = await client.checkMFARequired();\nawait client.verifyMFA(cachedFactorId, code);\n// after\nconst mfa = await client.checkMFARequired();\nif (!mfa.required || !mfa.factorId) return; // no MFA needed\nawait client.verifyMFA(mfa.factorId, code); // fresh factorId every attempt","handlingStrategy":"validation","validationCode":"const mfa = await client.checkMFARequired();\nif (!mfa.required || typeof mfa.factorId !== 'string') {\n  throw new Error('No verified MFA factor available for challenge');\n}\n// proceed to verifyMFA(mfa.factorId, code)","typeGuard":"function hasVerifiedFactor(m: { required: boolean; factorId?: string }): m is { required: true; factorId: string } {\n  return m.required === true && typeof m.factorId === 'string' && m.factorId.length > 0;\n}","tryCatchPattern":"try {\n  await client.verifyMFA(factorId, code);\n} catch (e) {\n  if (e instanceof AuthenticationError && e.code === 'MFA_VERIFICATION_FAILED') {\n    // refresh factor list via checkMFARequired() and re-challenge\n    const fresh = await client.checkMFARequired();\n    if (fresh.required && fresh.factorId) await client.verifyMFA(fresh.factorId, code);\n  } else throw e;\n}","preventionTips":["Always fetch a fresh factorId via checkMFARequired() instead of caching it.","Ensure a valid AAL1 session exists before starting the MFA challenge.","Handle user factor changes (unenroll/re-enroll) between sessions.","Avoid rapid repeated challenges to stay under Supabase rate limits."],"tags":["auth","mfa","totp","supabase"],"backgroundTag":"mfa-challenge-failed","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}