{"record":{"id":"4870723cf5d1986b","repo":"hcengineering/platform","slug":"contact-not-found-487072","errorCode":null,"errorMessage":"contact not found","messagePattern":"contact not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/recruit-resources/src/components/review/CreateReview.svelte","lineNumber":99,"sourceCode":"  const dispatch = createEventDispatcher()\n  const client = getClient()\n  const hierarchy = client.getHierarchy()\n\n  export function canClose (): boolean {\n    return (preserveCandidate || candidate === undefined) && title.length === 0\n  }\n\n  async function createReview () {\n    const sequence = await client.findOne(core.class.Sequence, { attachedTo: recruit.class.Review })\n    if (sequence === undefined) {\n      throw new Error('sequence object not found')\n    }\n\n    const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)\n\n    const candidateInstance = await client.findOne(contact.class.Person, { _id: doc.attachedTo as Ref<Person> })\n    if (candidateInstance === undefined) {\n      throw new Error('contact not found')\n    }\n    if (!client.getHierarchy().hasMixin(candidateInstance, recruit.mixin.Candidate)) {\n      await client.createMixin<Person, Candidate>(\n        candidateInstance._id,\n        candidateInstance._class,\n        candidateInstance.space,\n        recruit.mixin.Candidate,\n        {}\n      )\n    }\n\n    const ref = await client.addCollection(\n      recruit.class.Review,\n      doc.space,\n      doc.attachedTo,\n      doc.attachedToClass,\n      'reviews',\n      {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/recruit-resources/src/components/review/CreateReview.svelte#L81-L117","documentation":"After incrementing the sequence, CreateReview.svelte fetches the Person the review is attached to via `doc.attachedTo`. If the lookup fails, the candidate cannot be resolved/mixin'd and it throws 'contact not found'. This means the review dialog's attachedTo id does not point to an existing contact.class.Person document.","triggerScenarios":"Creating a review when `client.findOne(contact.class.Person, { _id: doc.attachedTo })` returns undefined — the person was deleted, the id is stale, or the doc.attachedTo points at a non-Person document.","commonSituations":"Candidate deleted by another user while the review dialog was open; stale/offline client cache; dialog opened from a wrong context passing a non-person id; permission filtering hiding the person record.","solutions":["Refresh client data and reopen the review dialog with a valid candidate.","Include the failing id in the error message to diagnose the broken reference.","Validate before submission that doc.attachedTo resolves to an existing Person.","Check whether the candidate was soft-deleted or filtered out by permissions."],"exampleFix":"// before\nconst candidateInstance = await client.findOne(contact.class.Person, { _id: doc.attachedTo as Ref<Person> })\nif (candidateInstance === undefined) {\n  throw new Error('contact not found')\n}\n// after\nconst candidateInstance = await client.findOne(contact.class.Person, { _id: doc.attachedTo as Ref<Person> })\nif (candidateInstance === undefined) {\n  throw new Error(`person not found: ${String(doc.attachedTo)}`)\n}","handlingStrategy":"type-guard","validationCode":"const person = await client.findOne(contact.class.Person, { _id: doc.attachedTo as Ref<Person> })\nif (person === undefined) {\n  console.error('person missing', doc.attachedTo)\n  return\n}","typeGuard":"function personExists(p: Person | undefined): p is Person { return p !== undefined }","tryCatchPattern":"try {\n  await createReview()\n} catch (e) {\n  if (e.message === 'contact not found') {\n    showNotification('The candidate no longer exists; refresh and reopen the dialog')\n  } else throw e\n}","preventionTips":["Verify the candidate still exists before opening the review dialog","Refresh stale client caches after offline periods","Confirm dialog context always passes a Person id as attachedTo"],"tags":["database","missing-data","stale-reference"],"backgroundTag":"referenced-document-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}