{"record":{"id":"ec072e44811ad6aa","repo":"calcom/cal.diy","slug":"email-already-exists","errorCode":null,"errorMessage":"Email already exists","messagePattern":"Email already exists","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apps/api/v2/src/modules/atoms/services/verification-atom.service.ts","lineNumber":122,"sourceCode":"\n    return verifiedEmails;\n  }\n\n  async addVerifiedEmail({\n    userId,\n    existingPrimaryEmail,\n    email,\n  }: {\n    userId: number;\n    existingPrimaryEmail: string;\n    email: string;\n  }): Promise<boolean> {\n    const existingSecondaryEmail =\n      await this.atomsSecondaryEmailsRepository.getExistingSecondaryEmailByUserAndEmail(userId, email);\n    const alreadyExistingEmail = await this.atomsSecondaryEmailsRepository.getExistingSecondaryEmail(email);\n\n    if (alreadyExistingEmail) {\n      throw new BadRequestException(\"Email already exists\");\n    }\n\n    if (existingPrimaryEmail === email || existingSecondaryEmail === email) {\n      return true;\n    }\n\n    await this.atomsSecondaryEmailsRepository.addSecondaryEmailVerified(userId, email);\n\n    return true;\n  }\n\n  removeClientIdFromEmail(email: string): string {\n    const [localPart, domain] = email.split(\"@\");\n    const localPartSegments = localPart.split(\"+\");\n\n    localPartSegments.pop();\n\n    const baseEmail = localPartSegments.join(\"+\");","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/atoms/services/verification-atom.service.ts#L104-L140","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Tell the end user to choose a different email, or to remove the secondary email from the other account first.","If you believe this is stale data, inspect atoms_secondary_emails for the email and confirm whether the owning user still claims it.","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)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before offering 'add secondary email', check it isn't already taken globally\nconst existing = await atomsSecondaryEmailsRepository.getExistingSecondaryEmail(email);\nif (existing) {\n  throw new BadRequestException('Email already exists');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await service.addSecondaryEmail({ userId, existingPrimaryEmail, email });\n} catch (e) {\n  if (e instanceof BadRequestException && e.message === 'Email already exists') {\n    // prompt user for a different email\n  }\n  throw e;\n}","preventionTips":["Run a pre-flight availability check before sending the verification code to avoid wasted email sends.","Normalize/trim/lowercase the email before lookup so casing doesn't bypass the duplicate check."],"tags":["verification","secondary-email","duplicate","business-rule","atoms-api"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}