{"record":{"id":"58bb38663fabd8f1","repo":"medusajs/medusa","slug":"auth-identity-does-not-have-any-enabled-mfa-method","errorCode":null,"errorMessage":"Auth identity does not have any enabled MFA methods","messagePattern":"Auth identity does not have any enabled MFA methods","errorType":"exception","errorClass":"MedusaError","httpStatus":403,"severity":"error","filePath":"packages/modules/auth/src/services/auth-module.ts","lineNumber":443,"sourceCode":"\n  @InjectTransactionManager()\n  protected async createAuthMfaChallenge_(\n    data: AuthTypes.CreateAuthMfaChallengeDTO,\n    @MedusaContext() sharedContext: Context = {}\n  ): Promise<AuthTypes.AuthMfaChallengeDTO> {\n    await this.authIdentityService_.retrieve(\n      data.auth_identity_id,\n      {},\n      sharedContext\n    )\n\n    const methods = await this.getAvailableMfaChallengeMethods_(\n      data.auth_identity_id,\n      sharedContext\n    )\n\n    if (!methods.length) {\n      throw new MedusaError(\n        MedusaError.Types.NOT_ALLOWED,\n        \"Auth identity does not have any enabled MFA methods\"\n      )\n    }\n\n    const challengeConfig = this.getMfaChallengeConfig_()\n    const challenge: AuthTypes.AuthMfaChallengeDTO = {\n      id: generateEntityId(undefined, \"authmfachal\"),\n      auth_identity_id: data.auth_identity_id,\n      auth_provider: data.auth_provider ?? null,\n      methods,\n      expires_at: new Date(Date.now() + challengeConfig.ttlSeconds * 1000),\n      attempts: 0,\n      max_attempts: challengeConfig.maxAttempts,\n      completed_at: null,\n      metadata: data.metadata ?? null,\n    }\n","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/auth/src/services/auth-module.ts#L425-L461","documentation":"Creating an MFA challenge requires at least one enabled MFA method on the auth identity. If getAvailableMfaChallengeMethods_ returns an empty list, challenge creation is refused with NOT_ALLOWED.","triggerScenarios":"createAuthMfaChallenge for an identity that has no factors with status 'enabled' — e.g. only a pending (never confirmed) TOTP setup exists, or all factors were disabled.","commonSituations":"Login flow always tries to challenge; user abandoned MFA setup halfway so nothing is enabled; factors disabled by admin leaving the account without MFA.","solutions":["Skip the challenge step when no enabled factors exist — check listAuthMfaFactors and filter status === 'enabled'","Have the user complete (or redo) their MFA setup so an enabled factor exists"],"exampleFix":"// before\nconst challenge = await authModuleService.createAuthMfaChallenge({ auth_identity_id: id })\n// after\nconst enabled = (await authModuleService.listAuthMfaFactors(id))\n  .filter((f) => f.status === 'enabled')\nif (enabled.length) {\n  const challenge = await authModuleService.createAuthMfaChallenge({\n    auth_identity_id: id,\n  })\n}","handlingStrategy":"validation","validationCode":"const enabled = (await authModuleService.listAuthMfaFactors(identityId)).filter((f) => f.status === 'enabled')\nif (enabled.length) await authModuleService.createAuthMfaChallenge({ auth_identity_id: identityId })","typeGuard":"const hasEnabledFactor = (factors: { status: string }[]) => factors.some((f) => f.status === 'enabled')","tryCatchPattern":"try { await createAuthMfaChallenge(...) } catch (e) { if (e.message.includes('any enabled MFA')) { /* skip challenge, proceed without MFA */ } throw e }","preventionTips":["Branch the login flow on whether the identity has enabled factors","Prompt users who abandoned setup to finish enabling MFA"],"tags":["auth","mfa","challenge"],"backgroundTag":"no-enabled-mfa-method","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}