{"record":{"id":"9e28b082993f3511","repo":"hcengineering/platform","slug":"cannot-resolve-a-projectdocument-for-document-do","errorCode":null,"errorMessage":"Cannot resolve a ProjectDocument for document ${document._id}","messagePattern":"Cannot resolve a ProjectDocument for document (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/controlled-documents-resources/src/utils.ts","lineNumber":208,"sourceCode":"      },\n      sort: {\n        '$lookup.project.createdOn': SortingOrder.Descending\n      },\n      limit: 1\n    }\n  )\n\n  const project = projectDoc?.project ?? documents.ids.NoProject\n\n  return getProjectDocumentLink(targetDocument, project)\n}\n\nexport async function getControlledDocumentLinkFragment (document: ControlledDocument): Promise<Location> {\n  const client = getClient()\n  const targetDocument = await client.findOne(documents.class.ProjectDocument, { document: document._id })\n\n  if (targetDocument === undefined) {\n    throw new Error('Cannot resolve a ProjectDocument for document ' + document._id)\n  }\n\n  const project = targetDocument.project ?? documents.ids.NoProject\n  return getProjectDocumentLink(document, project)\n}\n\nexport interface TeamPopupData {\n  controlledDoc: ControlledDocument\n  requestClass: Ref<Class<DocumentRequest>>\n  requireSignature?: boolean\n}\n\nexport async function sendReviewRequest (\n  client: TxOperations,\n  controlledDoc: ControlledDocument,\n  reviewers: Array<Ref<Employee>>\n): Promise<void> {\n  const approveTx = client.txFactory.createTxUpdateDoc(controlledDoc._class, controlledDoc.space, controlledDoc._id, {","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/controlled-documents-resources/src/utils.ts#L190-L226","documentation":"getControlledDocumentLinkFragment looks up the ProjectDocument that references a given ControlledDocument via findOne on { document: document._id } and throws when no such ProjectDocument exists. The library requires every controlled document link to resolve to a project document to build a valid location.","triggerScenarios":"Requesting a link fragment for a ControlledDocument whose backing ProjectDocument was never created or was deleted; passing a _id from another hierarchy or a stale reference.","commonSituations":"Data migration creating controlled documents without project documents; hard-deleting project documents while controlled documents remain; UI/bookmarks referencing removed documents.","solutions":["Create the missing ProjectDocument linked to the controlled document via { document: document._id }","Restore the deleted ProjectDocument or remove the orphaned ControlledDocument","Guard callers to check existence with client.findOne before requesting a link fragment","Fix creation flow so a ProjectDocument is always created alongside the controlled document"],"exampleFix":"// before\nconst loc = await getControlledDocumentLinkFragment(doc) // throws\n// after\nconst pd = await client.findOne(documents.class.ProjectDocument, { document: doc._id })\nif (pd === undefined) return undefined\nconst loc = await getControlledDocumentLinkFragment(doc)","handlingStrategy":"validation","validationCode":"const pd = await client.findOne(documents.class.ProjectDocument, { document: controlledDoc._id })\nif (pd === undefined) return undefined // or create the missing ProjectDocument","typeGuard":"async function hasProjectDocument(client: Client, doc: ControlledDocument): Promise<boolean> {\n  return (await client.findOne(documents.class.ProjectDocument, { document: doc._id })) !== undefined\n}","tryCatchPattern":"try {\n  return await getControlledDocumentLinkFragment(doc)\n} catch (err) {\n  if (err.message.startsWith('Cannot resolve a ProjectDocument')) {\n    return undefined\n  }\n  throw err\n}","preventionTips":["Always create the ProjectDocument alongside its ControlledDocument","Use soft-delete so controlled documents never outlive their project document","Check existence with findOne before requesting link fragments","Validate referential integrity after data migrations"],"tags":["controlled-documents","link-resolution","missing-document"],"backgroundTag":"document-not-resolvable","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}