{"record":{"id":"be80f80b61b3b95a","repo":"hcengineering/platform","slug":"accountalreadyexists-be80f8","errorCode":"AccountAlreadyExists","errorMessage":"An account with the provided email already exists","messagePattern":"An account with the provided email already exists","errorType":"exception","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"server/account/src/operations.ts","lineNumber":374,"sourceCode":"    lastName?: string\n  }\n): Promise<OtpInfo> {\n  const { email, firstName, lastName } = params\n\n  if (email == null || firstName == null || email === '' || firstName === '') {\n    throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {}))\n  }\n\n  // Note: can support OTP based on any other social logins later\n  const normalizedEmail = cleanEmail(email)\n  let emailSocialId = await getEmailSocialId(db, normalizedEmail)\n  let personUuid: PersonUuid\n\n  if (emailSocialId !== null) {\n    const existingAccount = await db.account.findOne({ uuid: emailSocialId.personUuid as AccountUuid })\n\n    if (existingAccount !== null) {\n      ctx.warn('An account with the provided email already exists', { email })\n      throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountAlreadyExists, {}))\n    }\n\n    await db.person.update({ uuid: emailSocialId.personUuid }, { firstName, lastName: lastName ?? '' })\n\n    personUuid = emailSocialId.personUuid\n  } else {\n    // There's no person linked to this email, so we need to create a new one\n    personUuid = await db.person.insertOne({ firstName, lastName: lastName ?? '' })\n    const newSocialId = { type: SocialIdType.EMAIL, value: normalizedEmail, personUuid }\n    const emailSocialIdId = await db.socialId.insertOne(newSocialId)\n    emailSocialId = { ...newSocialId, _id: emailSocialIdId, key: buildSocialIdString(newSocialId) }\n  }\n\n  return await sendOtp(ctx, db, branding, emailSocialId)\n}\n\n/**","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server/account/src/operations.ts#L356-L392","documentation":"In signUpOtp, the email social id already resolves to a person that has an existing account, so a new signup would duplicate it. The server throws AccountAlreadyExists instead of proceeding with account creation.","triggerScenarios":"Calling signUpOtp with an email whose social id (emailSocialId) is already linked to an account — i.e. the person already completed signup, or a partial signup previously created the account.","commonSituations":"Double-submitting the signup form; retrying signup after a timeout when the first request actually succeeded; users signing up again after switching login methods; migration leaving a verified social id attached to an existing account.","solutions":["Detect the AccountAlreadyExists status and route the user to the login / password-reset flow instead of signup.","Have the user sign in with the original method (social login or password) tied to that email.","If the account is truly orphaned, an admin can unlink or remove the duplicate account record.","Disable the signup submit button while the request is in-flight to prevent double submission."],"exampleFix":"// before\nawait client.signUpOtp(email, firstName, lastName) // throws on duplicate\n// after\ntry {\n  await client.signUpOtp(email, firstName, lastName)\n} catch (e) {\n  if (isStatusError(e, platform.status.AccountAlreadyExists)) {\n    redirectToLogin(email)\n    return\n  }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"const existing = await lookupAccountByEmail(email)\nif (existing != null) redirectToLogin(email)","typeGuard":"function isAccountAlreadyExists(e: unknown): boolean {\n  return e instanceof PlatformError && e.status.code === platform.status.AccountAlreadyExists\n}","tryCatchPattern":"try {\n  await client.signUpOtp(email, firstName, lastName)\n} catch (e) {\n  if (isAccountAlreadyExists(e)) {\n    redirectToLogin(email)\n    return\n  }\n  throw e\n}","preventionTips":["Check email availability before showing the signup form.","Disable the submit button while signup is in-flight to avoid double submission.","Route duplicate-email users to login/password-reset instead of signup."],"tags":["account","signup","duplicate-email"],"backgroundTag":"account-already-exists","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}