paperclipai/paperclip · error
Photon publication is empty
Error message
Photon publication is empty
What it means
Thrown at the end of PhotonAdapter.publish when no part was ever sent, i.e. lastId remained undefined after the text-parts and file loops. This happens when splitPhotonText produced zero parts and there were no files — the publication would have no content at all, so the adapter aborts instead of returning an empty receipt.
Solutions
- Guard the caller: check that textOf(message) is non-empty (or files non-empty) before calling publish
- Fix the upstream step that produced the empty response instead of publishing an empty publication
- Coalesce empty publications into a placeholder ('(no output)') only if the product allows it
Example fix
// before
await adapter.publish(id, pubId, emptyMessage, opts);
// after
const text = textOf(message);
if (!text.trim() && !(message.files?.length)) {
throw new EmptyPublicationError();
}
await adapter.publish(id, pubId, message, opts); Defensive patterns
Strategy: validation
Validate before calling
const text = textOf(message);
if (!text?.trim() && !(message.files?.length))
throw new Error('Refusing to publish an empty publication'); Type guard
function isNonEmptyPublication(msg) {
return Boolean(textOf(msg)?.trim()) || Boolean(msg.files?.length);
} Try / catch
try {
await adapter.publish(id, pubId, msg, opts);
} catch (e) {
if (e.message === 'Photon publication is empty') {
log.error('empty publication', { publicationId: pubId });
return null; // nothing to deliver
}
throw e;
} Prevention
- Validate non-empty text or files at the call site
- Guard upstream agent steps against producing empty output
- Be careful with sanitizers/transformations that can strip all content
- Add a unit test for empty-message publish behavior
When it happens
Trigger: publish() with an empty/whitespace-only text that splitPhotonText reduces to zero parts and an empty files array.
Common situations: An upstream agent produced an empty response; a message body was stripped to nothing by formatting/sanitization; a code path passed `undefined`/empty string as the message text while forgetting to include attachments.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- A full lowercase source SHA is required.
- A reusable lease cannot be replaced and reacquired in the…
- A reusable lease handoff requires an execution workspace…
- A safe, unique --revision is required
- A same-run reusable lease reacquisition requires a…
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/96608b9bcd7d59ac.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/photon/adapter.ts:461
? Buffer.from(await file.data.arrayBuffer())
: Buffer.from(file.data as ArrayBuffer);
if (bytes.length > MAX_ATTACHMENT_BYTES)
throw new Error("Attachment exceeds the configured size limit");
lastId = await this.sendPart(
publicationId,
`file-${index}`,
{
chatGuid: chat.guid,
filename: file.filename,
sha256: createHash("sha256").update(bytes).digest("hex"),
replyTo: options.replyTo,
},
{ ...file, data: bytes },
options,
);
messageIds.push(lastId);
}
if (!lastId) throw new Error("Photon publication is empty");
await this.endTyping(id);
return { id: lastId, messageIds };
}
private async sendPart(
publicationId: string,
part: string,
payload: {
chatGuid: string;
text?: string;
filename?: string;
sha256?: string;
replyTo?: string;
replaceMessageId?: string;
},
file: FileUpload | undefined,
options: { retryUnknown?: boolean; assertCurrent(): Promise<void> },
): Promise<string> {
const key = `send:${publicationId}:${part}`;View on GitHub (pinned to 3f1d897a7c)