{"record":{"id":"381acfab9cb4c6fa","repo":"hcengineering/platform","slug":"platform-status-socialidalreadyexists","errorCode":"platform.status.SocialIdAlreadyExists","errorMessage":"throw new PlatformError(\n          new Status(Severity.ERROR, platform.status.SocialIdAlreadyExists, { value: email, type: SocialIdType.EMAIL })\n        )","messagePattern":"throw new PlatformError\\(\n          new Status\\(Severity\\.ERROR, platform\\.status\\.SocialIdAlreadyExists, (.+?)\\)\n        \\)","errorType":"exception","errorClass":"PlatformError","httpStatus":409,"severity":"error","filePath":"server/account/src/operations.ts","lineNumber":2905,"sourceCode":"\n  if (account == null) {\n    throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account }))\n  }\n\n  const normalizedEmail = normalizeValue(email)\n  const existing = await db.socialId.findOne({ type: SocialIdType.EMAIL, value: normalizedEmail })\n\n  // This schema should be applied to all types in general, they should only differ by the verification process.\n  // If none exists, create a new one and proceed to verification\n  // If exists only for person without account - will be able to merge person to the account, proceed to verification\n  // If exists for this account but not verified - proceed to verification right away\n  // If exists for this account and verified - throw an error (already exists)\n  // If exists for another account and not verified - will move only this id to the current account, proceed to verification\n  // If exists for another account and verified - throw an error for now, support merge accounts later, maybe through a different procedure\n  let targetSocialId: SocialId\n  if (existing != null) {\n    if (existing.verifiedOn != null) {\n      throw new PlatformError(\n        new Status(Severity.ERROR, platform.status.SocialIdAlreadyExists, { value: email, type: SocialIdType.EMAIL })\n      )\n    }\n    targetSocialId = existing\n  } else {\n    const newSocialId = {\n      type: SocialIdType.EMAIL,\n      value: normalizedEmail,\n      personUuid: account\n    }\n    const _id = await db.socialId.insertOne(newSocialId)\n    targetSocialId = { ...newSocialId, _id, key: buildSocialIdString(newSocialId) }\n  }\n\n  return await sendOtp(ctx, db, branding, targetSocialId)\n}\n\nasync function addHulyAssistantSocialId (","sourceCodeStart":2887,"sourceCodeEnd":2923,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server/account/src/operations.ts#L2887-L2923","documentation":"addEmailSocialId checks whether the normalized email already exists as a verified EMAIL social id. Per the documented policy, if the social id exists and is verified — for this or another account — it throws platform.status.SocialIdAlreadyExists carrying the value and type. Unverified duplicates are reclaimed/moved instead of erroring; only verified ones collide.","triggerScenarios":"Adding an email that is already verified on another account (email reused after old signup), or re-adding an email the same account already verified. Also duplicate signup flows racing where one verification completed first.","commonSituations":"User forgot an old account with that email exists; trying to link a work email already bound to a colleague's account; test emails reused across accounts; password-manager autofill filling an already-registered email.","solutions":["Sign in with the existing account that owns this verified email instead of adding it to another account.","Choose a different, unregistered email address.","If the old account is yours and unreachable, use password recovery or account merge/support procedure, then retry.","Verify with an email lookup which account owns the address before attempting to link it."],"exampleFix":"// before\nawait accountClient.addEmailSocialId(token, { email: 'user@example.com' }) // already verified elsewhere\n// after\nconst owner = await findAccountByEmail('user@example.com')\nif (owner != null) {\n  showNotice('This email is already registered. Sign in or recover that account.')\n  return\n}\nawait accountClient.addEmailSocialId(token, { email: 'user@example.com' })","handlingStrategy":"try-catch","validationCode":"// Pre-check whether the email is already registered/verified elsewhere\nconst existing = await lookupAccountByEmail(email)\nif (existing != null && existing.verified) {\n  showNotice('This email is already registered. Sign in instead.')\n  return\n}","typeGuard":"function isUnclaimed (s: SocialId | null): s is null | (SocialId & { verifiedOn: null }) {\n  return s == null || s.verifiedOn == null\n}","tryCatchPattern":"try {\n  await accountClient.addEmailSocialId(token, { email })\n} catch (err) {\n  if (err instanceof PlatformError && err.status.code === platform.status.SocialIdAlreadyExists) {\n    showError('This email is already verified on another account. Sign in with it or use a different email.')\n  } else throw err\n}","preventionTips":["Check email availability before offering the add-email flow in the UI.","Prompt users to sign in with existing verified emails rather than re-linking.","Route duplicate-email cases to account recovery/merge flows.","Normalize emails (lowercase/trim) consistently to avoid false duplicates and missed ones."],"tags":["duplicate-email","social-id","conflict","account-service"],"backgroundTag":"email-already-exists","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}