paperclipai/paperclip · error

Photon conversation is unavailable

Error message

Photon conversation is unavailable

What it means

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.

Solutions

  1. Check the chat's archived state before publishing (chatInfo(id).isArchived) and surface a user-visible 'conversation archived' state instead of retrying
  2. Have the user unarchive the conversation in iMessage, then re-publish with the same publicationId
  3. Route the publication to a different (active) thread or workspace conversation
  4. Do not blindly retry: the check is deterministic and will keep failing while the chat stays archived

Example fix

// before
await adapter.publish(threadId, pubId, message, opts);
// after
const chat = await adapter.chatInfo(threadId);
if (chat.isArchived) throw new ConversationArchivedError(threadId);
await adapter.publish(threadId, pubId, message, opts);
Defensive patterns

Strategy: validation

Validate before calling

const chat = await adapter.chatInfo(threadId);
if (chat.isArchived) throw new Error(`Conversation ${threadId} is archived; cannot publish`);

Type guard

function isPublishable(chat) { return !chat.isArchived; }

Try / catch

try {
  await adapter.publish(id, pubId, msg, opts);
} catch (e) {
  if (e.message === 'Photon conversation is unavailable') {
    markPublicationBlocked(pubId, 'conversation-archived');
    return; // do not retry
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/1fd48048dcd89941. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/photon/adapter.ts:413

    /* Receipt reactions are intentionally not published. */
  }
  async removeReaction(): Promise<void> {
    /* Reactions never represent approvals. */
  }

  async publish(
    id: string,
    publicationId: string,
    message: AdapterPostableMessage,
    options: {
      replyTo?: string;
      replaceMessageId?: string;
      retryUnknown?: boolean;
      assertCurrent(): Promise<void>;
    },
  ): Promise<{ id: string; messageIds: string[] }> {
    const chat = await this.chatInfo(id);
    if (chat.isArchived) throw new Error("Photon conversation is unavailable");
    const text = textOf(message);
    const files =
      typeof message !== "string" && "files" in message
        ? (message.files ?? [])
        : [];
    const parts = splitPhotonText(text);
    if (options.replaceMessageId && (parts.length !== 1 || files.length))
      throw new Error("Photon cannot edit a multipart publication");
    let lastId: string | undefined;
    const messageIds: string[] = [];
    for (let index = 0; index < parts.length; index++) {
      lastId = await this.sendPart(
        publicationId,
        `text-${index}`,
        {
          chatGuid: chat.guid,
          text: parts[index],
          replyTo: options.replyTo,

View on GitHub (pinned to 3f1d897a7c)