calcom/cal.diy · error · BadRequestException

Email already exists

Error message

Email already exists

What it means

BadRequestException('Email already exists') from VerificationAtomService when adding a secondary email. It fires when atomsSecondaryEmailsRepository.getExistingSecondaryEmail(email) finds that the supplied email is already registered as a secondary email anywhere in the system — preventing duplicate email ownership across accounts. This is a real, live business-rule guard (unlike 20-25).

Source

Thrown at apps/api/v2/src/modules/atoms/services/verification-atom.service.ts:122

    return verifiedEmails;
  }

  async addVerifiedEmail({
    userId,
    existingPrimaryEmail,
    email,
  }: {
    userId: number;
    existingPrimaryEmail: string;
    email: string;
  }): Promise<boolean> {
    const existingSecondaryEmail =
      await this.atomsSecondaryEmailsRepository.getExistingSecondaryEmailByUserAndEmail(userId, email);
    const alreadyExistingEmail = await this.atomsSecondaryEmailsRepository.getExistingSecondaryEmail(email);

    if (alreadyExistingEmail) {
      throw new BadRequestException("Email already exists");
    }

    if (existingPrimaryEmail === email || existingSecondaryEmail === email) {
      return true;
    }

    await this.atomsSecondaryEmailsRepository.addSecondaryEmailVerified(userId, email);

    return true;
  }

  removeClientIdFromEmail(email: string): string {
    const [localPart, domain] = email.split("@");
    const localPartSegments = localPart.split("+");

    localPartSegments.pop();

    const baseEmail = localPartSegments.join("+");

View on GitHub (pinned to 176037d0af)

Solutions

  1. Tell the end user to choose a different email, or to remove the secondary email from the other account first.
  2. If you believe this is stale data, inspect atoms_secondary_emails for the email and confirm whether the owning user still claims it.
  3. Verify the request isn't accidentally re-submitting the user's already-owned secondary email via the global lookup (the own-email check is separate at line 130).
Defensive patterns

Strategy: validation

Validate before calling

// Before offering 'add secondary email', check it isn't already taken globally
const existing = await atomsSecondaryEmailsRepository.getExistingSecondaryEmail(email);
if (existing) {
  throw new BadRequestException('Email already exists');
}

Try / catch

try {
  await service.addSecondaryEmail({ userId, existingPrimaryEmail, email });
} catch (e) {
  if (e instanceof BadRequestException && e.message === 'Email already exists') {
    // prompt user for a different email
  }
  throw e;
}

Prevention

When it happens

Trigger: POST to add a secondary email (atoms flow) with an email that already exists in the atoms_secondary_emails table for any user. Note: only the global secondary-email lookup triggers this; the user's own primary/secondary emails take the early-return path at line 130 (existingPrimaryEmail === email || existingSecondaryEmail === email).

Common situations: User tries to add an email they already registered as secondary on another account; email was freed from another account but the row still exists; test fixtures seed duplicate emails; user mistakes another account's email for their own.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/ec072e44811ad6aa. Report an issue: GitHub.