medusajs/medusa · error · MedusaError
NOT_ALLOWED
NOT_ALLOWED
Error message
Recovery codes require an enabled MFA factor
What it means
Thrown by POST /auth/mfa/recovery-codes when the requesting auth identity has no MFA factor with status 'enabled'. Recovery codes are only generated as a backup for an active factor, so at least one enabled factor must exist first. Maps to HTTP 403 (NOT_ALLOWED).
Source
Thrown at packages/medusa/src/api/auth/mfa/recovery-codes/route.ts:23
import { IAuthModuleService } from "@medusajs/framework/types"
import { AuthEvents, MedusaError, Modules } from "@medusajs/framework/utils"
import { AuthMfaGenerateRecoveryCodesRequestType } from "../../validators"
/**
* @since 2.15.3
*/
export const POST = async (
req: AuthenticatedMedusaRequest<AuthMfaGenerateRecoveryCodesRequestType>,
res: MedusaResponse
) => {
const authService = req.scope.resolve<IAuthModuleService>(Modules.AUTH)
const factors = await authService.listAuthMfa({
auth_identity_id: req.auth_context.auth_identity_id,
status: "enabled",
})
if (!factors.length) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
"Recovery codes require an enabled MFA factor"
)
}
const { codes } = await authService.generateAuthMfaRecoveryCodes({
auth_identity_id: req.auth_context.auth_identity_id,
count: req.validatedBody.count,
})
await req.scope.resolve(Modules.EVENT_BUS).emit({
name: AuthEvents.MFA_RECOVERY_CODES_GENERATED,
data: {
auth_identity_id: req.auth_context.auth_identity_id,
count: codes.length,
},
})
View on GitHub (pinned to 5e06e544a2)
Solutions
- Create and verify an MFA factor first (register the factor, confirm the OTP, so its status becomes enabled)
- Call the MFA factors list endpoint and confirm status=enabled before requesting recovery codes
- If factors exist but are pending, complete their verification flow
- Re-enable a disabled factor or create a new one
Defensive patterns
Strategy: validation
Validate before calling
const factors = await authService.listAuthMfa({ auth_identity_id, status: 'enabled' })
if (!factors.length) {
throw new Error('Enable an MFA factor before requesting recovery codes')
} Type guard
function hasEnabledFactor(factors: { status: string }[]): boolean {
return factors.some((f) => f.status === 'enabled')
} Try / catch
catch (e) { if (e.type === 'not_allowed' && /enabled MFA factor/.test(e.message)) startFactorEnrollment() else throw e } Prevention
- Sequence onboarding: enroll factor → verify → generate recovery codes
- Check factor status before calling recovery-codes endpoints
When it happens
Trigger: Calling recovery code generation before any MFA factor was created and enabled, or after all factors were disabled.
Common situations: Client calls the recovery-codes endpoint too early in onboarding; factor created but still in 'pending' status (not yet verified/enabled); factors disabled during account recovery.
Related errors
- INVALID_DATA
- An active TOTP factor already exists for this auth identity
- Only TOTP MFA factors can be verified with this method
- Disabled MFA factors cannot be verified
- Invalid TOTP code
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/136495f3de5ffbe6.
Report an issue: GitHub.