medusajs/medusa · error · MedusaError

Verification code is invalid or already used

Error message

Verification code is invalid or already used

What it means

The verification token lookup either found no matching record or found one already consumed (verified_at set). Codes are single-use, so reuse or wrong codes are both rejected with NOT_ALLOWED.

Source

Thrown at packages/modules/auth/src/providers/verification/token.ts:119

    if (!data.code) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        "Verification code is required"
      )
    }

    const [verification] = await this.authVerificationService_.list(
      {
        provider_metadata: {
          token_hash: hashVerificationToken(data.code),
        },
      },
      {},
      sharedContext
    )

    if (!verification || verification.verified_at) {
      throw new MedusaError(
        MedusaError.Types.NOT_ALLOWED,
        "Verification code is invalid or already used"
      )
    }

    if (
      data.code_provider &&
      data.code_provider !== verification.code_provider
    ) {
      throw new MedusaError(
        MedusaError.Types.NOT_ALLOWED,
        `Verification code does not belong to provider "${data.code_provider}"`
      )
    }

    const expiresAt =
      new Date(verification.requested_at).getTime() + this.getTokenTtlMs_()

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Request/generate a new verification code and confirm once with it
  2. Disable the submit button after first click to prevent double confirmation
  3. Verify the code string is passed exactly as delivered (no whitespace/encoding issues)
Defensive patterns

Strategy: validation

Validate before calling

// guard against double-submit
if (confirming) return
setConfirming(true)
try { await confirm(...) } finally { setConfirming(false) }

Try / catch

try { await confirm(...) } catch (e) { if (e.message.includes('invalid or already used')) { /* request new code */ } throw e }

Prevention

When it happens

Trigger: confirm() with a code that doesn't match any verification record, or confirming the same verification twice — the second call sees verified_at set and throws.

Common situations: Double-submitting the confirm form; retrying after a timeout when the first confirm succeeded; user typing the code wrong; expired/rotated token.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/7e1da372e03b59ea. Report an issue: GitHub.