{"record":{"id":"9072e55d71f40c3b","repo":"hcengineering/platform","slug":"card-not-found-id-ref","errorCode":null,"errorMessage":"Card not found, _id: ${ref}","messagePattern":"Card not found, _id: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/card-resources/src/utils.ts","lineNumber":462,"sourceCode":"  }\n\n  if (special === 'cards') {\n    return base\n  }\n\n  const client = getClient()\n  const object = await client.findOne(card.class.Card, { _id: special as Ref<Card> })\n\n  if (object === undefined) {\n    return base\n  }\n\n  return { name: object.title }\n}\n\nexport async function getCardTitle (client: TxOperations, ref: Ref<Card>, doc?: Card): Promise<string> {\n  const object = doc ?? (await client.findOne(card.class.Card, { _id: ref }))\n  if (object === undefined) throw new Error(`Card not found, _id: ${ref}`)\n  const h = client.getHierarchy()\n  const attrs = [...h.getAllAttributes(object._class, core.class.Doc).values()].sort((a, b) => {\n    const rankA = a.rank ?? toRank(a._id) ?? ''\n    const rankB = b.rank ?? toRank(b._id) ?? ''\n    return rankA.localeCompare(rankB)\n  })\n  const res: string[] = []\n  for (const attr of attrs) {\n    const val = (object as any)[attr.name]\n    if (attr.showInPresenter === true && val !== undefined) {\n      if (typeof val === 'string' || typeof val === 'number') {\n        res.push(val.toString())\n      } else if (typeof val === 'boolean') {\n        res.push(val ? '✅' : '❌️')\n      }\n    }\n  }\n","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/card-resources/src/utils.ts#L444-L480","documentation":"getCardTitle resolves a Card by ref (or accepts a preloaded doc). If no doc is passed and findOne finds no Card with that _id in the workspace, it cannot compute a title and throws with the missing ref.","triggerScenarios":"Calling getCardTitle with a Ref<Card> that no longer exists (deleted card), an id from another workspace, a stale reference cached in a UI, or a typo'd ref — without supplying the optional doc argument.","commonSituations":"Notifications/attachments referencing cards deleted afterward; cross-workspace data copy; rendering card titles from cached refs after data cleanup; race where card is deleted between listing and title fetch.","solutions":["Verify the card ref exists in this workspace before calling, or pass the already-loaded doc","Handle deletion: skip title lookup for refs whose card no longer exists","Use findOne yourself and render a fallback label like 'Deleted card' when undefined"],"exampleFix":"// before\nconst title = await getCardTitle(client, ref) // throws if deleted\n// after\nconst doc = await client.findOne(card.class.Card, { _id: ref })\nconst title = doc !== undefined ? await getCardTitle(client, ref, doc) : 'Deleted card'","handlingStrategy":"validation","validationCode":"const doc = docArg ?? await client.findOne(card.class.Card, { _id: ref })\nif (doc === undefined) return 'Deleted card' // fallback instead of calling getCardTitle","typeGuard":"const cardExists = async (client: TxOperations, ref: Ref<Card>): Promise<boolean> =>\n  (await client.findOne(card.class.Card, { _id: ref })) !== undefined","tryCatchPattern":"try {\n  title = await getCardTitle(client, ref)\n} catch (err) {\n  if ((err as Error).message.startsWith('Card not found')) {\n    title = 'Deleted card'\n  } else throw err\n}","preventionTips":["Pass the already-loaded Card as the doc argument whenever available","Clean up references (notifications, attachments) when a card is deleted","Render fallback titles for stale refs in UI listings"],"tags":["card","missing-data","reference"],"backgroundTag":"document-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}