calcom/cal.diy · error · BadRequestException
Verification failed
Error message
Verification failed
What it means
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.
Source
Thrown at apps/api/v2/src/modules/atoms/services/verification-atom.service.ts:40
) {}
async checkEmailVerificationRequired(input: CheckEmailVerificationRequiredParams) {
return await checkEmailVerificationRequired(input);
}
async verifyEmailCodeUnAuthenticated(input: VerifyEmailCodeInput) {
try {
return await verifyCodeUnAuthenticated(input.email, input.code);
} catch (error) {
if (error instanceof Error) {
if (error.message === "invalid_code") {
throw new BadRequestException("Invalid verification code");
}
if (error.message === "BAD_REQUEST") {
throw new BadRequestException("Email and code are required");
}
}
throw new BadRequestException("Verification failed");
}
}
async verifyEmailCodeAuthenticated(user: UserWithProfile, input: VerifyEmailCodeInput) {
try {
return await verifyCodeAuthenticated({
user,
email: input.email,
code: input.code,
});
} catch (error) {
if (error instanceof Error) {
if (error.message === "invalid_code") {
throw new BadRequestException("Invalid verification code");
}
if (error.message === "BAD_REQUEST") {
throw new BadRequestException("Email, code, and user ID are required");
}View on GitHub (pinned to 176037d0af)
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'.
Example fix
// before
throw new BadRequestException("Verification failed");
// after — preserve the real cause for distinguishable client errors
throw new BadRequestException(error instanceof Error ? error.message : "Verification failed"); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check inputs to avoid the generic fallback
if (!input.email || !input.code) {
throw new BadRequestException('Email and code are required');
}
// Pre-check the code format to avoid a wasted TOTP attempt
if (!/^\d{4,8}$/.test(input.code)) {
throw new BadRequestException('Code must be 4-8 digits');
} Try / catch
try {
await service.verifyEmailCodeUnAuthenticated(input);
} catch (e) {
if (e instanceof BadRequestException) {
// 'Verification failed' — could be wrong code, missing input, OR rate limit.
// Surface a 're-enter code' UX; offer to resend.
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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'.
Common situations: 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.
Related errors
- Invalid verification code
- Email and code are required
- Email, code, and user ID are required
- Email already exists
- ${err.message}
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/14c586bfd8a38be2.
Report an issue: GitHub.