{"record":{"id":"926c49a8965cc1b9","repo":"eyaltoledano/claude-task-master","slug":"mfa-required-incomplete","errorCode":"MFA_REQUIRED_INCOMPLETE","errorMessage":"'MFA is required but the server returned incomplete factor configuration. Please contact support or try re-enrolling MFA.'","messagePattern":"'MFA is required but the server returned incomplete factor configuration\\. Please contact support or try re-enrolling MFA\\.'","errorType":"exception","errorClass":"AuthenticationError","httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/modules/auth/services/oauth-service.ts","lineNumber":456,"sourceCode":"\t */\n\tgetAuthorizationUrl(): string | null {\n\t\treturn this.authorizationUrl;\n\t}\n\n\t/**\n\t * Check if MFA is required and throw appropriate error if so\n\t * This ensures OAuth flow enforces MFA when user has it enabled\n\t */\n\tprivate async checkAndThrowIfMFARequired(): Promise<void> {\n\t\tconst mfaCheck = await this.supabaseClient.checkMFARequired();\n\n\t\tif (mfaCheck.required) {\n\t\t\t// MFA is required - check if we have complete factor information\n\t\t\tif (!mfaCheck.factorId || !mfaCheck.factorType) {\n\t\t\t\tthis.logger.error('MFA required but factor information is incomplete', {\n\t\t\t\t\tmfaCheck\n\t\t\t\t});\n\t\t\t\tthrow new AuthenticationError(\n\t\t\t\t\t'MFA is required but the server returned incomplete factor configuration. Please contact support or try re-enrolling MFA.',\n\t\t\t\t\t'MFA_REQUIRED_INCOMPLETE'\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.logger.info('MFA verification required after OAuth login', {\n\t\t\t\tfactorId: mfaCheck.factorId,\n\t\t\t\tfactorType: mfaCheck.factorType\n\t\t\t});\n\n\t\t\tconst mfaChallenge: MFAChallenge = {\n\t\t\t\tfactorId: mfaCheck.factorId,\n\t\t\t\tfactorType: mfaCheck.factorType\n\t\t\t};\n\n\t\t\tthrow new AuthenticationError(\n\t\t\t\t'MFA verification required. Please provide your authentication code.',\n\t\t\t\t'MFA_REQUIRED',","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/auth/services/oauth-service.ts#L438-L474","documentation":"Thrown by checkAndThrowIfMFARequired in OAuthService when the backend signals that MFA is required after an OAuth/PKCE login, but the MFA challenge response is missing factorId or factorType. Without both fields the library cannot construct a valid MFAChallenge, so instead of asking the user for a code it fails fast with MFA_REQUIRED_INCOMPLETE. This indicates a server-side contract violation rather than a user error.","triggerScenarios":"authenticateWithBackendPKCE completes OAuth and calls the MFA-check endpoint; the response has required=true but factorId or factorType is missing/null/undefined (e.g. a factor row missing from Supabase MFA config, a malformed mfaCheck payload, or an API version returning a different shape).","commonSituations":"Backend API updated and changed the MFA response shape; user's MFA factor was partially deleted or never fully enrolled so the server reports required without factor details; proxy/gateway stripping fields; mismatched @tm/core and server versions.","solutions":["Have the user re-enroll MFA (factor is incomplete on the server) and retry login","Verify the backend MFA-check endpoint returns both factorId and factorType when required=true","Check @tm/core and server API versions match; upgrade @tm/core to the latest","Inspect the logged mfaCheck object (logger.error output) to see which field is missing","Retry authentication once in case of a transient server-side read glitch"],"exampleFix":"// before: user stuck with incomplete factor data\nawait tmCore.auth.loginWithOAuth();\n// after: detect incomplete MFA and prompt re-enrollment\ntry {\n  await tmCore.auth.loginWithOAuth();\n} catch (e) {\n  if (e instanceof AuthenticationError && e.code === 'MFA_REQUIRED_INCOMPLETE') {\n    console.error('Re-enroll MFA at https://server/mfa, then retry login');\n  }\n}","handlingStrategy":"try-catch","validationCode":"// No client-side pre-check possible; the defect is in the server payload.\n// Validate the challenge AFTER catching, before continuing the MFA flow:\nfunction hasCompleteChallenge(e: unknown): e is AuthenticationError & { details: { factorId: string; factorType: string } } {\n  return e instanceof AuthenticationError &&\n    e.code === 'MFA_REQUIRED' &&\n    typeof (e.details as any)?.factorId === 'string' &&\n    typeof (e.details as any)?.factorType === 'string';\n}","typeGuard":"function isIncompleteMfaError(e: unknown): e is AuthenticationError {\n  return e instanceof AuthenticationError && e.code === 'MFA_REQUIRED_INCOMPLETE';\n}","tryCatchPattern":"try {\n  await tmCore.auth.loginWithOAuth();\n} catch (e) {\n  if (isIncompleteMfaError(e)) {\n    console.error('Server returned incomplete MFA config. Re-enroll MFA and retry.', e.code);\n    // surface to user: direct them to re-enrollment, do not prompt for a code\n  } else throw e;\n}","preventionTips":["Keep @tm/core and the server API on compatible versions","Re-enroll MFA promptly if a factor shows as incomplete in account settings","Monitor server logs for mfaCheck payloads missing factorId/factorType","Add an integration test asserting the MFA-check endpoint always returns both fields when required=true"],"tags":["mfa","oauth","api-contract","authentication"],"backgroundTag":"mfa-factor-config-incomplete","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}