{"record":{"id":"75b1d69950aa14ac","repo":"hcengineering/platform","slug":"confirmed-social-identity-is-attached-to-the-wrong","errorCode":null,"errorMessage":"Confirmed social identity is attached to the wrong person","messagePattern":"Confirmed social identity is attached to the wrong person","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/contact/src/utils.ts","lineNumber":528,"sourceCode":"                attachedToClass: contact.class.Person,\n                collection: 'socialIds',\n                type: socialId.type,\n                value: socialId.value,\n                key: buildSocialIdString(socialId), // TODO: fill it in trigger or on DB level as stored calculated column or smth?\n                verifiedOn: socialId.verifiedOn,\n                isDeleted: socialId.isDeleted ?? false\n              },\n              socialId._id as SocialIdentityRef\n            )\n          )\n          await client.tx(createSocialIdTx)\n        })\n      } else {\n        // If not confirmed locally can be attached to a different person (persons merge scenario)\n        // Confirmed social identity should not be attached to a different person for now\n        // It will change with accounts merge function\n        if (existing.verifiedOn != null && existing.attachedTo !== personRef) {\n          throw new Error('Confirmed social identity is attached to the wrong person')\n        }\n\n        // Check and update if needed. It can:\n        // 1. Become verified (maybe with persons merge) (changes verifiedOn, attachedTo)\n        const sidUpdate: DocumentUpdate<SocialIdentity> = {}\n        let needUpdate = false\n\n        // become verified\n        if (existing.verifiedOn == null) {\n          sidUpdate.verifiedOn = socialId.verifiedOn\n          needUpdate = true\n        }\n\n        // merged from another person\n        if (existing.attachedTo !== personRef) {\n          sidUpdate.attachedTo = personRef\n          // Bump collection in Person?\n          needUpdate = true","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/contact/src/utils.ts#L510-L546","documentation":"ensureEmployeeForPerson validates that a confirmed (verifiedOn set) social identity is not attached to a different person than the one being processed. Unconfirmed identities may move between persons (merge scenarios), but confirmed ones must not, so the function throws to protect data integrity until an accounts-merge feature exists.","triggerScenarios":"Merging or re-attributing persons where a SocialIdentity has verifiedOn set and attachedTo pointing at a different personRef than the target person; calling ensureEmployee for a person whose identity record belongs to someone else.","commonSituations":"Duplicate-person cleanup scripts merging two employees who shared a verified social login; import/migration tooling re-linking identities; concurrent person-merge operations racing.","solutions":["Verify the correct person owns the confirmed identity; unmerge or detach the identity from the wrong person first","Reset verifiedOn (unconfirm) the identity if it genuinely needs reassignment, then re-verify under the right person","Skip or reconcile the conflicting person before running the merge","Fix upstream merge logic so identities are re-pointed before ensureEmployee runs"],"exampleFix":"// before\nawait ensureEmployee(client, personA) // identity.verifiedOn set, attachedTo = personB\n// after\nawait client.update(identity, { attachedTo: personA, verifiedOn: Date.now() })\nawait ensureEmployee(client, personA)","handlingStrategy":"validation","validationCode":"const existing = identities.find(i => i.key === sid)\nif (existing?.verifiedOn != null && existing.attachedTo !== person._id) {\n  // reconcile identity ownership before calling ensureEmployee\n}","typeGuard":"function isSafeToAttach(identity: SocialIdentity | undefined, personRef: Ref<Person>): boolean {\n  return identity === undefined || identity.verifiedOn == null || identity.attachedTo === personRef\n}","tryCatchPattern":"try {\n  await ensureEmployee(client, person)\n} catch (err) {\n  if (err.message.includes('Confirmed social identity is attached to the wrong person')) {\n    // resolve identity ownership conflict manually / via admin tooling\n  }\n  throw err\n}","preventionTips":["Before merging persons, re-point or unconfirm conflicting verified identities","Audit social identities for verifiedOn/attachedTo consistency before bulk merges","Sequence merge operations to avoid concurrent identity reassignment","Document that verified identities cannot be silently moved between persons"],"tags":["data-integrity","social-identity","merge"],"backgroundTag":"identity-attached-to-wrong-person","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}