{"record":{"id":"0cfc843ba8b7253f","repo":"medusajs/medusa","slug":"verification-code-has-expired","errorCode":null,"errorMessage":"Verification code has expired","messagePattern":"Verification code has expired","errorType":"exception","errorClass":"MedusaError","httpStatus":403,"severity":"error","filePath":"packages/modules/auth/src/providers/verification/token.ts","lineNumber":139,"sourceCode":"        \"Verification code is invalid or already used\"\n      )\n    }\n\n    if (\n      data.code_provider &&\n      data.code_provider !== verification.code_provider\n    ) {\n      throw new MedusaError(\n        MedusaError.Types.NOT_ALLOWED,\n        `Verification code does not belong to provider \"${data.code_provider}\"`\n      )\n    }\n\n    const expiresAt =\n      new Date(verification.requested_at).getTime() + this.getTokenTtlMs_()\n\n    if (expiresAt <= Date.now()) {\n      throw new MedusaError(\n        MedusaError.Types.NOT_ALLOWED,\n        \"Verification code has expired\"\n      )\n    }\n\n    return await this.authVerificationService_.update(\n      {\n        id: verification.id,\n        verified_at: new Date(Date.now()),\n      },\n      sharedContext\n    )\n  }\n\n  protected getTokenTtlMs_(): number {\n    return getVerificationTokenTtlMs(this.options_.ttl_seconds ?? 900)\n  }\n}","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/auth/src/providers/verification/token.ts#L121-L157","documentation":"The verification code exists and is unused, but requested_at + TTL is in the past, so the code is expired and confirmation is rejected. TTL comes from the token provider's getTokenTtlMs_().","triggerScenarios":"Confirming a verification more than the configured TTL (commonly 10–15 minutes) after it was requested; also triggered by long-delayed queue processing or a user returning to a stale form.","commonSituations":"User waits too long before entering the code; TTL misconfigured very low; email delivery delays pushing real elapsed time past the window.","solutions":["Trigger a new verification request to get a fresh code","Increase the TTL configuration if legitimate users routinely exceed it","Start the expiry timer from when the email is actually sent, not queued, if delivery is slow"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// show countdown client-side based on requested_at + TTL\nconst expired = Date.now() > requestedAt + TTL_MS\nif (expired) await resendCode()","typeGuard":null,"tryCatchPattern":"try { await confirm(...) } catch (e) { if (e.message.includes('expired')) { await resendCode() } throw e }","preventionTips":["Auto-expire the input UI after the TTL and offer resend","Keep TTL generous enough for email delivery latency"],"tags":["auth","verification","expiry"],"backgroundTag":"otp-expired","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}