{"record":{"id":"14c586bfd8a38be2","repo":"calcom/cal.diy","slug":"verification-failed","errorCode":null,"errorMessage":"Verification failed","messagePattern":"Verification failed","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apps/api/v2/src/modules/atoms/services/verification-atom.service.ts","lineNumber":40,"sourceCode":"  ) {}\n\n  async checkEmailVerificationRequired(input: CheckEmailVerificationRequiredParams) {\n    return await checkEmailVerificationRequired(input);\n  }\n\n  async verifyEmailCodeUnAuthenticated(input: VerifyEmailCodeInput) {\n    try {\n      return await verifyCodeUnAuthenticated(input.email, input.code);\n    } catch (error) {\n      if (error instanceof Error) {\n        if (error.message === \"invalid_code\") {\n          throw new BadRequestException(\"Invalid verification code\");\n        }\n        if (error.message === \"BAD_REQUEST\") {\n          throw new BadRequestException(\"Email and code are required\");\n        }\n      }\n      throw new BadRequestException(\"Verification failed\");\n    }\n  }\n\n  async verifyEmailCodeAuthenticated(user: UserWithProfile, input: VerifyEmailCodeInput) {\n    try {\n      return await verifyCodeAuthenticated({\n        user,\n        email: input.email,\n        code: input.code,\n      });\n    } catch (error) {\n      if (error instanceof Error) {\n        if (error.message === \"invalid_code\") {\n          throw new BadRequestException(\"Invalid verification code\");\n        }\n        if (error.message === \"BAD_REQUEST\") {\n          throw new BadRequestException(\"Email, code, and user ID are required\");\n        }","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/atoms/services/verification-atom.service.ts#L22-L58","documentation":"The fallback BadRequestException('Verification failed') in verifyEmailCodeUnAuthenticated — fires for ANY upstream error whose message is not 'invalid_code' or 'BAD_REQUEST'. Because those two predicates never match the real upstream strings (see errors 20/21), THIS is the error that actually surfaces for almost every failure: wrong code, expired code, missing email/code, and rate-limit errors all collapse into this generic 400. The original cause is swallowed, which makes debugging hard.","triggerScenarios":"Any POST to the unauthenticated verify endpoint whose upstream verifyCodeUnAuthenticated throws — including wrong code (Error 'Invalid verification code'), missing fields (Error 'Email and code are required'), or checkRateLimitAndThrowError rate-limit exhaustion. All resolve to 'Verification failed'.","commonSituations":"End user types the wrong code; code expired past the 900s TOTP step; too many verify attempts tripped the core rate limiter on identifier emailVerifyCode.<hash>; CALENDSO_ENCRYPTION_KEY mismatch between issuer and verifier; client omitted email or code.","solutions":["Re-request a verification code and submit it immediately within the 15-minute TOTP window.","Confirm CALENDSO_ENCRYPTION_KEY is the same on the issuing and verifying service.","If under heavy retry, wait for the rate-limit window to reset (identifier is keyed on the email hash).","As a platform maintainer: widen the catch to preserve the upstream message (or rethrow typed ErrorWithCode) so 'wrong code' vs 'rate limited' vs 'missing input' are distinguishable instead of all mapping to 'Verification failed'."],"exampleFix":"// before\nthrow new BadRequestException(\"Verification failed\");\n\n// after — preserve the real cause for distinguishable client errors\nthrow new BadRequestException(error instanceof Error ? error.message : \"Verification failed\");","handlingStrategy":"try-catch","validationCode":"// Pre-check inputs to avoid the generic fallback\nif (!input.email || !input.code) {\n  throw new BadRequestException('Email and code are required');\n}\n// Pre-check the code format to avoid a wasted TOTP attempt\nif (!/^\\d{4,8}$/.test(input.code)) {\n  throw new BadRequestException('Code must be 4-8 digits');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await service.verifyEmailCodeUnAuthenticated(input);\n} catch (e) {\n  if (e instanceof BadRequestException) {\n    // 'Verification failed' — could be wrong code, missing input, OR rate limit.\n    // Surface a 're-enter code' UX; offer to resend.\n  }\n  throw e;\n}","preventionTips":["Submit the code immediately after generation (900s window).","Back off after a failure to avoid the core rate limiter keyed on emailVerifyCode.<hash>.","As maintainer: differentiate wrong-code from rate-limit from missing-input so callers can react appropriately."],"tags":["verification","catch-all","rate-limit","totp","atoms-api"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}