paperclipai/paperclip · error · PhotonError

rejected

rejected

Error message

Photon shared channels support direct messages only

What it means

encodeThreadId converts a PhotonThread into its string thread id. If the thread is a group chat but the authenticated identity uses a 'shared' allocation, it throws PhotonError('rejected', ...) because shared Photon channels only support direct-message threads. It also throws 'Wrong Photon line' if the thread belongs to a different line.

Solutions

  1. Use a direct-message thread (isGroup === false) with the shared allocation identity.
  2. Re-allocate the identity as a dedicated (non-shared) allocation if group messaging is required.
  3. Update routing so group threads map to a dedicated-line identity before calling encodeThreadId.

Example fix

// before
const threadId = adapter.encodeThreadId(groupThread);
// after
if (groupThread.isGroup && identity.allocation === "shared") {
  throw new UnsupportedGroupError(); // route group sends through a dedicated identity
}
const threadId = adapter.encodeThreadId(groupThread);
Defensive patterns

Strategy: validation

Validate before calling

if (thread.isGroup && identity.allocation === "shared") throw new Error("group threads require a dedicated Photon allocation");

Type guard

const canEncode = (t) => !(t.isGroup && authentication.identity.allocation === "shared");

Try / catch

let id;
try {
  id = adapter.encodeThreadId(thread);
} catch (e) {
  if (e.message.includes("shared channels")) { routeToDedicatedIdentity(thread); return; }
  throw e;
}

Prevention

When it happens

Trigger: Encoding a group PhotonThread while the adapter's authentication identity has allocation === 'shared'; e.g. sending/posting to a group channel over a shared-channel identity.

Common situations: An identity allocated as 'shared' (shared Photon channel) being reused for group messaging; a config or allocation change switched the identity from dedicated to shared while existing group threads are still addressed.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        channelOptions: {
          "grpc.max_receive_message_length": MAX_ATTACHMENT_BYTES + 1024 * 1024,
        },
      });
  }
  async initialize(_chat: ChatInstance): Promise<void> {
    await this.authentication.token();
  }
  async disconnect(): Promise<void> {
    this.closed = true;
    for (const timer of this.typing.values()) clearTimeout(timer);
    this.typing.clear();
    this.authentication.retire();
    this.recovery?.close();
    await this.client.close();
  }
  encodeThreadId(value: PhotonThread): string {
    if (value.isGroup && this.authentication.identity.allocation === "shared")
      throw new PhotonError("rejected", "Photon shared channels support direct messages only");
    if (value.lineId !== this.authentication.identity.lineId)
      throw new Error("Wrong Photon line");
    return photonThreadId(value);
  }
  decodeThreadId(id: string): PhotonThread {
    const value = parsePhotonThreadId(id);
    if (value.isGroup && this.authentication.identity.allocation === "shared")
      throw new PhotonError("rejected", "Photon shared channels support direct messages only");
    if (value.lineId !== this.authentication.identity.lineId)
      throw new Error("Wrong Photon line");
    return value;
  }
  channelIdFromThreadId(id: string): string {
    this.decodeThreadId(id);
    return id;
  }
  isDM(id: string): boolean {
    return !this.decodeThreadId(id).isGroup;

View on GitHub (pinned to 3f1d897a7c)