{"record":{"id":"661ed65d3f88dc7d","repo":"hcengineering/platform","slug":"conflict","errorCode":"Conflict","errorMessage":"Verifying new social id belonging to person w/o account but it's already verified","messagePattern":"Verifying new social id belonging to person w/o account but it's already verified","errorType":"exception","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"server/account/src/operations.ts","lineNumber":484,"sourceCode":"      if (callerAccountUuid == null) {\n        throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, {}))\n      }\n\n      if (targetAccount == null) {\n        // only person exists means there's no verified social id associated with it -> merge it to the current account\n        // doMergePersons will fail if there's a verified social id\n\n        await doMergePersons(db, callerAccountUuid, emailSocialId.personUuid)\n\n        // what happens to local persons referencing this person in various workspaces?\n        // there can be some persons but no Employees because there's no account\n        // we know where the person is migrated to so can update later as needed\n\n        if (emailSocialId.verifiedOn == null) {\n          await db.socialId.update({ _id: emailSocialId._id }, { verifiedOn: Date.now() })\n        } else {\n          // Normally, it should not be the case\n          ctx.warn(\"Verifying new social id belonging to person w/o account but it's already verified\", {\n            emailSocialId,\n            callerAccountUuid\n          })\n          throw new PlatformError(new Status(Severity.ERROR, platform.status.Conflict, {}))\n        }\n      } else {\n        if (callerAccountUuid === targetAccount.uuid) {\n          if (emailSocialId.verifiedOn == null) {\n            await db.socialId.update({ _id: emailSocialId._id }, { verifiedOn: Date.now() })\n          }\n        } else {\n          if (emailSocialId.verifiedOn == null) {\n            // Move the target social id to current account, we can easily do this because it was not verified\n            await db.socialId.update(\n              { _id: emailSocialId._id },\n              { personUuid: callerAccountUuid, verifiedOn: Date.now() }\n            )\n          } else {","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server/account/src/operations.ts#L466-L502","documentation":"In validateOtp, while verifying a new email social id that belongs to a person who has no account yet, the social id turns out to already have verifiedOn set — which should be impossible at this point. The server treats it as an inconsistent state and throws Conflict.","triggerScenarios":"Calling validateOtp with a callerAccountUuid whose person has an email social id that was already verified (verifiedOn != null) through a prior OTP validation or a migration that pre-verified ids.","commonSituations":"Replaying/resharing the same OTP validation request; concurrent OTP validation from two sessions; data migrations that set verifiedOn on social ids for account-less persons, breaking the assumption in this code path.","solutions":["Avoid duplicate validateOtp calls for the same social id — make the request idempotent client-side.","If hit after a migration, correct the data: either clear verifiedOn or link an account to the person, so state matches the expected invariant.","Retry the signup flow from the beginning to generate a fresh social id/OTP.","Check for concurrent sessions validating the same email and serialize the flow."],"exampleFix":"// before\nawait client.validateOtp(otp) // may throw Conflict on replay\n// after\nif (!otpValidationPending) return // already validated\ntry {\n  await client.validateOtp(otp)\n  otpValidationPending = false\n} catch (e) {\n  if (isStatusError(e, platform.status.Conflict)) refreshSignupState()\n  else throw e\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function isConflictStatus(e: unknown): boolean {\n  return e instanceof PlatformError && e.status.code === platform.status.Conflict\n}","tryCatchPattern":"try {\n  await client.validateOtp(otp)\n} catch (e) {\n  if (isConflictStatus(e)) {\n    // already verified: treat as success or restart signup flow\n    restartSignupFlow()\n    return\n  }\n  throw e\n}","preventionTips":["Make OTP validation idempotent — don't call validateOtp twice for the same social id.","Prevent concurrent OTP validation from multiple sessions/tabs.","After data migrations, verify social id verifiedOn state matches account existence."],"tags":["account","otp","conflict","state-inconsistency"],"backgroundTag":"social-id-already-verified-conflict","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}