{"record":{"id":"bbb681fcfafd3f41","repo":"paperclipai/paperclip","slug":"photon-attachment-does-not-belong-to-this-message-and-chat","errorCode":null,"errorMessage":"Photon attachment does not belong to this message and chat","messagePattern":"Photon attachment does not belong to this message and chat","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/photon/attachments.ts","lineNumber":94,"sourceCode":"  photonAttachmentLocatorSchema.parse(locator);\n  if (locator.lineId !== lineId)\n    throw new Error(\"Photon attachment belongs to another line\");\n  const source = await client.messages\n    .get(locator.messageGuid)\n    .catch((error) => {\n      throw photonFailure(error);\n    });\n  const attachment = source.content.attachments.find(\n    (candidate) => candidate.guid === locator.attachmentGuid,\n  );\n  if (\n    source.guid !== locator.messageGuid ||\n    !source.chatGuids.includes(locator.chatGuid) ||\n    !attachment ||\n    attachment.isSticker ||\n    attachment.isHidden\n  )\n    throw new Error(\n      \"Photon attachment does not belong to this message and chat\",\n    );\n  if (\n    !Number.isSafeInteger(attachment.totalBytes) ||\n    attachment.totalBytes < 0 ||\n    attachment.totalBytes > MAX_ATTACHMENT_BYTES\n  )\n    throw new Error(\"Attachment exceeds the configured size limit\");\n  const stream = client.attachments.downloadStream(locator.attachmentGuid);\n  let timedOut = false;\n  const timer = setTimeout(() => {\n    timedOut = true;\n    void stream.close();\n  }, 30_000);\n  timer.unref();\n  const chunks: Uint8Array[] = [];\n  let length = 0;\n  let header = false;","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/photon/attachments.ts#L76-L112","documentation":"After fetching the source message via client.messages.get(locator.messageGuid), the code verifies the returned message's guid, its chat list, and that the attachment exists on it and is neither a sticker nor hidden. If any check fails, it throws that the attachment does not belong to this message and chat (server/src/services/photon/attachments.ts:94). It is a consistency/ownership guard against stale or forged locators.","triggerScenarios":"The fetched message's guid differs from locator.messageGuid; locator.chatGuid is not in source.chatGuids; no attachment with locator.attachmentGuid exists on the message; or the matching attachment is flagged isSticker or isHidden.","commonSituations":"Stale locator pointing at a message that was edited or deleted and re-created; attachment was a sticker or hidden asset that later got filtered; GUID casing/format mismatch between gateway aliases and native UUIDs; locator built from a different message than the one fetched.","solutions":["Rebuild the locator from the current message with photonAttachmentLocator() so chatGuid, messageGuid, and attachmentGuid are consistent.","Confirm the attachment is a regular (non-sticker, non-hidden) attachment on the message before downloading.","Verify locator.messageGuid and locator.chatGuid match a message that still exists in the Photon chat store.","For shared-gateway aliases, ensure the source-message lookup ran so ownership is established before the download RPC."],"exampleFix":"// before\nconst locator = oldStoredLocator; // may point at edited/hidden attachment\nawait downloadPhotonAttachment(client, lineId, locator);\n// after\nconst locator = photonAttachmentLocator(attachment, lineId, chatGuid, message);\nif (!locator) throw new Error(\"attachment is not downloadable on this message\");\nawait downloadPhotonAttachment(client, lineId, locator);","handlingStrategy":"validation","validationCode":"const locator = photonAttachmentLocator(attachment, lineId, chatGuid, message);\nif (!locator) throw new Error(\"attachment not downloadable on this message/chat\");\nconst raw = message.raw as PhotonMessage;\nconst att = raw.content?.attachments.find(a => a.guid === locator.attachmentGuid);\nif (!att || att.isSticker || att.isHidden) throw new Error(\"attachment hidden or sticker\");","typeGuard":"function isDownloadable(att: Attachment | undefined): att is Attachment {\n  return !!att && !att.isSticker && !att.isHidden;\n}","tryCatchPattern":"try {\n  await downloadPhotonAttachment(client, lineId, locator);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"does not belong to this message and chat\")) {\n    // refresh message metadata and rebuild the locator, or skip the attachment\n  } else throw e;\n}","preventionTips":["Rebuild locators from fresh message state instead of caching them","Pre-filter stickers and hidden attachments before attempting download","Confirm messageGuid/chatGuid/attachmentGuid all come from the same fetched message"],"tags":["ownership-check","attachments","stale-reference"],"backgroundTag":"resource-not-found","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}