{"record":{"id":"1fd48048dcd89941","repo":"paperclipai/paperclip","slug":"photon-conversation-is-unavailable","errorCode":null,"errorMessage":"Photon conversation is unavailable","messagePattern":"Photon conversation is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/photon/adapter.ts","lineNumber":413,"sourceCode":"    /* 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: {\n      replyTo?: string;\n      replaceMessageId?: string;\n      retryUnknown?: boolean;\n      assertCurrent(): Promise<void>;\n    },\n  ): Promise<{ id: string; messageIds: string[] }> {\n    const chat = await this.chatInfo(id);\n    if (chat.isArchived) throw new Error(\"Photon conversation is unavailable\");\n    const text = textOf(message);\n    const files =\n      typeof message !== \"string\" && \"files\" in message\n        ? (message.files ?? [])\n        : [];\n    const parts = splitPhotonText(text);\n    if (options.replaceMessageId && (parts.length !== 1 || files.length))\n      throw new Error(\"Photon cannot edit a multipart publication\");\n    let lastId: string | undefined;\n    const messageIds: string[] = [];\n    for (let index = 0; index < parts.length; index++) {\n      lastId = await this.sendPart(\n        publicationId,\n        `text-${index}`,\n        {\n          chatGuid: chat.guid,\n          text: parts[index],\n          replyTo: options.replyTo,","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/photon/adapter.ts#L395-L431","documentation":"Thrown in PhotonAdapter.publish when the target iMessage chat (resolved via chatInfo) is marked archived. Photon treats archived conversations as unavailable delivery targets, so publication is refused before any send is attempted. It is a pre-flight guard, not a network failure.","triggerScenarios":"Calling publish(id, publicationId, message, options) where this.client.chats (fetched by chatInfo(id)) reports chat.isArchived === true — i.e. the conversation was archived in iMessage/Photon between publication preparation and this call.","commonSituations":"A user archived the chat in the Messages app while the agent run was still open; a rerun or replay targets a stale thread id; automated cleanup archived old chats so long-lived publications can no longer deliver.","solutions":["Check the chat's archived state before publishing (chatInfo(id).isArchived) and surface a user-visible 'conversation archived' state instead of retrying","Have the user unarchive the conversation in iMessage, then re-publish with the same publicationId","Route the publication to a different (active) thread or workspace conversation","Do not blindly retry: the check is deterministic and will keep failing while the chat stays archived"],"exampleFix":"// before\nawait adapter.publish(threadId, pubId, message, opts);\n// after\nconst chat = await adapter.chatInfo(threadId);\nif (chat.isArchived) throw new ConversationArchivedError(threadId);\nawait adapter.publish(threadId, pubId, message, opts);","handlingStrategy":"validation","validationCode":"const chat = await adapter.chatInfo(threadId);\nif (chat.isArchived) throw new Error(`Conversation ${threadId} is archived; cannot publish`);","typeGuard":"function isPublishable(chat) { return !chat.isArchived; }","tryCatchPattern":"try {\n  await adapter.publish(id, pubId, msg, opts);\n} catch (e) {\n  if (e.message === 'Photon conversation is unavailable') {\n    markPublicationBlocked(pubId, 'conversation-archived');\n    return; // do not retry\n  }\n  throw e;\n}","preventionTips":["Check chatInfo().isArchived before starting long agent runs","Surface archived-thread state in the UI before offering send actions","Avoid reusing thread ids across long-lived schedules without re-validating the chat","Treat this as terminal: never auto-retry an archived conversation"],"tags":["imessage","conversation-archived","precondition-failed"],"backgroundTag":"invalid-state-transition","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"}