{"record":{"id":"7002255f067016ea","repo":"paperclipai/paperclip","slug":"photon-edits-require-an-immutable-paperclip-publication","errorCode":null,"errorMessage":"Photon edits require an immutable Paperclip publication identity","messagePattern":"Photon edits require an immutable Paperclip publication identity","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/photon/adapter.ts","lineNumber":387,"sourceCode":"    if (!this.closed)\n      await this.client.chats\n        .setTyping(this.decodeThreadId(id).chatGuid, false)\n        .catch(() => {});\n  }\n  async postMessage(\n    _id: string,\n    _message: AdapterPostableMessage,\n  ): Promise<never> {\n    throw new Error(\n      \"Photon sends require an immutable Paperclip publication identity\",\n    );\n  }\n  async editMessage(\n    _id: string,\n    _messageId: string,\n    _message: AdapterPostableMessage,\n  ): Promise<never> {\n    throw new Error(\n      \"Photon edits require an immutable Paperclip publication identity\",\n    );\n  }\n  async deleteMessage(): Promise<never> {\n    throw new Error(\"Photon message deletion is not supported\");\n  }\n  async addReaction(): Promise<void> {\n    /* Receipt reactions are intentionally not published. */\n  }\n  async removeReaction(): Promise<void> {\n    /* Reactions never represent approvals. */\n  }\n\n  async publish(\n    id: string,\n    publicationId: string,\n    message: AdapterPostableMessage,\n    options: {","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/photon/adapter.ts#L369-L405","documentation":"Photon's editMessage is deliberately unimplemented: it always throws 'Photon edits require an immutable Paperclip publication identity'. Like postMessage, editing published Photon messages is refused because it would mutate content bound to an immutable publication identity.","triggerScenarios":"Any call to adapter.editMessage(chatId, messageId, message) on the Photon adapter.","commonSituations":"Shared messaging code that updates an earlier message (e.g. progress or status edits) across all adapters; retry logic that re-sends an edited payload through editMessage.","solutions":["Do not edit Photon messages; post a new publication or update state in Paperclip instead.","Gate edit paths behind an adapter capability flag and fall back to no-op or new-message for Photon.","Handle the thrown error in edit flows so a failed edit does not abort the surrounding workflow."],"exampleFix":"// before\nawait adapter.editMessage(chatId, messageId, updated);\n// after\nif (adapter.capabilities?.canEdit) {\n  await adapter.editMessage(chatId, messageId, updated);\n} // else: leave published message immutable\n","handlingStrategy":"type-guard","validationCode":"if (!adapter.capabilities?.canEdit) return; // Photon edits unsupported","typeGuard":"const canEdit = (a: unknown): a is AdapterWithEdit => (a as AdapterWithEdit).capabilities?.canEdit === true;","tryCatchPattern":"try {\n  await adapter.editMessage(chatId, messageId, updated);\n} catch (e) {\n  if (e.message.includes(\"edits require\")) { await publishFollowup(chatId, updated); return; }\n  throw e;\n}","preventionTips":["Gate edit flows behind per-adapter capability flags.","For Photon, publish corrections as new messages instead of editing.","Handle the capability error explicitly in shared edit helpers."],"tags":["photon","messaging","unsupported-operation"],"backgroundTag":"method-not-implemented","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"}