{"record":{"id":"7e1da372e03b59ea","repo":"medusajs/medusa","slug":"verification-code-is-invalid-or-already-used","errorCode":null,"errorMessage":"Verification code is invalid or already used","messagePattern":"Verification code is invalid or already used","errorType":"exception","errorClass":"MedusaError","httpStatus":403,"severity":"error","filePath":"packages/modules/auth/src/providers/verification/token.ts","lineNumber":119,"sourceCode":"    if (!data.code) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        \"Verification code is required\"\n      )\n    }\n\n    const [verification] = await this.authVerificationService_.list(\n      {\n        provider_metadata: {\n          token_hash: hashVerificationToken(data.code),\n        },\n      },\n      {},\n      sharedContext\n    )\n\n    if (!verification || verification.verified_at) {\n      throw new MedusaError(\n        MedusaError.Types.NOT_ALLOWED,\n        \"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","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/auth/src/providers/verification/token.ts#L101-L137","documentation":"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.","triggerScenarios":"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.","commonSituations":"Double-submitting the confirm form; retrying after a timeout when the first confirm succeeded; user typing the code wrong; expired/rotated token.","solutions":["Request/generate a new verification code and confirm once with it","Disable the submit button after first click to prevent double confirmation","Verify the code string is passed exactly as delivered (no whitespace/encoding issues)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// guard against double-submit\nif (confirming) return\nsetConfirming(true)\ntry { await confirm(...) } finally { setConfirming(false) }","typeGuard":null,"tryCatchPattern":"try { await confirm(...) } catch (e) { if (e.message.includes('invalid or already used')) { /* request new code */ } throw e }","preventionTips":["Disable submit button after first click","Treat confirmation as one-shot: on failure, always re-request a code"],"tags":["auth","verification","one-time-token"],"backgroundTag":"otp-already-used","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}