paperclipai/paperclip · error
Photon sends require an immutable Paperclip publication…
Error message
Photon sends require an immutable Paperclip publication identity
What it means
Photon's postMessage is deliberately unimplemented: it always throws 'Photon sends require an immutable Paperclip publication identity'. Photon messages published through Paperclip need a stable publication identity, and the adapter refuses ad-hoc sends that would break that immutability guarantee.
Solutions
- Do not call postMessage on the Photon adapter; treat Photon as read/receipt-only for outbound publication.
- Route outbound messages through the Paperclip publication-identity path instead of direct adapter sends.
- Feature-check before sending: skip or no-op Photon when the code path requires postMessage.
Example fix
// before
await adapter.postMessage(chatId, message);
// after
if (typeof adapter.postMessage === "function" && adapter.capabilities?.canPost) {
await adapter.postMessage(chatId, message);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (adapter === photonAdapter || !adapter.capabilities?.canPost) return; // Photon cannot post
Type guard
const canPost = (a: unknown): a is AdapterWithPost => typeof (a as AdapterWithPost).postMessage === "function" && (a as AdapterWithPost).capabilities?.canPost === true;
Try / catch
try {
await adapter.postMessage(chatId, msg);
} catch (e) {
if (e.message.includes("immutable Paperclip publication identity")) return; // Photon: sends unsupported
throw e;
} Prevention
- Maintain an explicit per-adapter capability map (post/edit/delete) and consult it before sends.
- Exclude Photon from generic outbound-notification loops.
- Use the Paperclip publication-identity path for any Photon-bound outbound content.
When it happens
Trigger: Any call to adapter.postMessage(chatId, message) on the Photon adapter, regardless of arguments.
Common situations: Generic notification or bot code that calls postMessage on every messaging adapter without excluding Photon; attempting to send agent replies through the Photon channel.
Related errors
- Photon edits require an immutable Paperclip publication…
- Photon message deletion is not supported
- rejected
- Photon message belongs to another chat
- ACPX runtime does not expose session goal controls
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/25fee57c00e4637b.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/photon/adapter.ts:378
this.typing.delete(id);
void this.refreshTyping(id, true).catch(() => {});
}, 8_000);
timer.unref();
this.typing.set(id, timer);
}
async endTyping(id: string): Promise<void> {
if (this.typing.has(id)) clearTimeout(this.typing.get(id));
this.typing.delete(id);
if (!this.closed)
await this.client.chats
.setTyping(this.decodeThreadId(id).chatGuid, false)
.catch(() => {});
}
async postMessage(
_id: string,
_message: AdapterPostableMessage,
): Promise<never> {
throw new Error(
"Photon sends require an immutable Paperclip publication identity",
);
}
async editMessage(
_id: string,
_messageId: string,
_message: AdapterPostableMessage,
): Promise<never> {
throw new Error(
"Photon edits require an immutable Paperclip publication identity",
);
}
async deleteMessage(): Promise<never> {
throw new Error("Photon message deletion is not supported");
}
async addReaction(): Promise<void> {
/* Receipt reactions are intentionally not published. */
}View on GitHub (pinned to 3f1d897a7c)