{"record":{"id":"30461ccfbea81412","repo":"hcengineering/platform","slug":"couldn-t-find-contact-by-id-channel-attachedto","errorCode":null,"errorMessage":"Couldn't find contact by id + channel.attachedTo","messagePattern":"Couldn't find contact by id \\+ channel\\.attachedTo","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services/telegram/pod-telegram/src/workspace.ts","lineNumber":323,"sourceCode":"    if (rec === undefined || rec?.phone === undefined) return\n    const client = this.clients.get(rec.phone)\n\n    if (client === undefined) {\n      throw Error('Failed to find connection')\n    }\n\n    const channel = this.channelsById.get(msg.attachedTo as Ref<Channel>)\n    if (channel === undefined) return\n    const target = normalizeValue(channel.value)\n\n    const importRequired = await client.conn.isContactImportRequired(target)\n\n    if (importRequired) {\n      const contact = await this.client.findOne<PContact>(channel.attachedToClass, {\n        _id: channel.attachedTo as Ref<PContact>\n      })\n      if (contact === undefined) {\n        throw new Error(\"Couldn't find contact by id\" + channel.attachedTo)\n      }\n\n      await client.conn.addContact({\n        lastName: getLastName(contact.name),\n        firstName: getFirstName(contact.name),\n        phone: target\n      })\n    }\n\n    const { message, entities } = platformToTelegram(msg.content)\n    const files = await this.getFiles(msg)\n    if (files.length < 2) {\n      const res = await client.conn.sendMsg(target, message, entities, files.shift())\n      const user = await res.getChat()\n\n      if (user?.className !== 'User') {\n        return\n      }","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/telegram/pod-telegram/src/workspace.ts#L305-L341","documentation":"sendMsg throws when the PContact referenced by channel.attachedTo cannot be found via findOne in the channel's attachedToClass. To add the Telegram contact before sending, the message needs the contact's name split into first/last name; a missing contact record breaks the outgoing message pipeline (txCreateDoc → res → sendNewMsgs).","triggerScenarios":"A message is sent on a channel whose attachedTo points to a deleted or never-created PContact document; data inconsistency between channels and contacts (e.g. contact removed by a migration or cascade delete) surfaces when sendNewMsgs processes the queue.","commonSituations":"Contacts deleted while their channels remained, partially completed imports/integrations, or workspace data restored from a backup where contacts were lost but channels survived.","solutions":["Inspect the channel document and re-create/restore the missing PContact with _id = channel.attachedTo.","Delete the orphaned channel so the message queue stops retrying the broken target.","Add a cascade rule so deleting a contact also removes (or detaches) its channels.","Wrap the send in a guard that logs and skips (or re-links) channels with missing contacts instead of throwing."],"exampleFix":"// before\nif (contact === undefined) {\n  throw new Error(\"Couldn't find contact by id\" + channel.attachedTo)\n}\n// after\nif (contact === undefined) {\n  ctx.warn('Skipping channel with missing contact', { channel: channel._id, contact: channel.attachedTo })\n  return // or re-link the channel to an existing contact\n}","handlingStrategy":"type-guard","validationCode":"const contact = await client.findOne<PContact>(channel.attachedToClass, { _id: channel.attachedTo as Ref<PContact> })\nif (contact === undefined) {\n  throw new Error(`Channel ${channel._id} references missing contact ${channel.attachedTo}; fix data before sending`)\n}","typeGuard":"function channelHasContact(channel: Channel, contact: PContact | undefined): contact is PContact {\n  return contact !== undefined && channel.attachedTo === (contact as PContact)._id\n}","tryCatchPattern":"try {\n  await sendMessage(channel, msg)\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Couldn't find contact by id\")) {\n    ctx.warn('Skipping channel with missing contact', { channel: channel._id })\n  } else throw err\n}","preventionTips":["Cascade-delete (or detach) channels when their contact is removed.","Run periodic integrity checks for channels with dangling attachedTo references.","Restore-verify backups for both contacts and channels together."],"tags":["telegram","missing-record","data-integrity","messaging"],"backgroundTag":"missing-contact-record","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}