paperclipai/paperclip · error
Attachment exceeds the configured size limit
Error message
Attachment exceeds the configured size limit
What it means
Before streaming, the message's attachment metadata (attachment.totalBytes) is validated: it must be a safe non-negative integer no larger than MAX_ATTACHMENT_BYTES. Otherwise this error is thrown (server/src/services/photon/attachments.ts:102). It guards against downloading absurdly large or corrupt-size attachments.
Solutions
- Check the attachment's totalBytes against MAX_ATTACHMENT_BYTES before calling and skip attachments that are too large.
- Raise MAX_ATTACHMENT_BYTES in server/src/attachment-types.js if the limit is unintentionally small.
- Treat non-numeric/missing totalBytes as a metadata problem: re-sync message metadata from Photon before downloading.
- Ask the sender to resend as a smaller/compressed attachment when the size genuinely exceeds the cap.
Example fix
// before await downloadPhotonAttachment(client, lineId, locator); // may throw for big files // after const att = message.raw.content.attachments.find(a => a.guid === locator.attachmentGuid); if (att.totalBytes > MAX_ATTACHMENT_BYTES) return skipAttachment(att, "too large"); await downloadPhotonAttachment(client, lineId, locator);
Defensive patterns
Strategy: validation
Validate before calling
import { MAX_ATTACHMENT_BYTES } from "../attachment-types.js";
const att = message.raw.content.attachments.find(a => a.guid === locator.attachmentGuid);
if (!Number.isSafeInteger(att?.totalBytes) || att.totalBytes < 0 || att.totalBytes > MAX_ATTACHMENT_BYTES) {
throw new Error(`attachment too large or invalid size: ${att?.totalBytes}`);
} Try / catch
try {
await downloadPhotonAttachment(client, lineId, locator);
} catch (e) {
if (e instanceof Error && e.message === "Attachment exceeds the configured size limit") {
// record and skip; do not retry
} else throw e;
} Prevention
- Check attachment.totalBytes against MAX_ATTACHMENT_BYTES before every download
- Keep the configured limit in sync with the largest media your users send
- Treat invalid/missing totalBytes metadata as a skip-and-log case, not a retry
When it happens
Trigger: attachment.totalBytes is undefined/NaN/not a safe integer, negative, or greater than MAX_ATTACHMENT_BYTES as configured in server/src/attachment-types.js.
Common situations: A user sends a multi-hundred-MB video exceeding the configured cap; Photon metadata is missing totalBytes for an older message format; misconfigured attachment-size limit lower than expected media sizes.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- Image exceeds attachment bound
- Completion cites no registered attachment on this task. Use…
- External chat attachment ids must be UUIDs
- External chat publications support at most
- github_attachment_source_mismatch
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/309f83d542a7651a.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/photon/attachments.ts:102
const attachment = source.content.attachments.find(
(candidate) => candidate.guid === locator.attachmentGuid,
);
if (
source.guid !== locator.messageGuid ||
!source.chatGuids.includes(locator.chatGuid) ||
!attachment ||
attachment.isSticker ||
attachment.isHidden
)
throw new Error(
"Photon attachment does not belong to this message and chat",
);
if (
!Number.isSafeInteger(attachment.totalBytes) ||
attachment.totalBytes < 0 ||
attachment.totalBytes > MAX_ATTACHMENT_BYTES
)
throw new Error("Attachment exceeds the configured size limit");
const stream = client.attachments.downloadStream(locator.attachmentGuid);
let timedOut = false;
const timer = setTimeout(() => {
timedOut = true;
void stream.close();
}, 30_000);
timer.unref();
const chunks: Uint8Array[] = [];
let length = 0;
let header = false;
let companionInfo: CompanionInfo | undefined;
let companionUnavailable = false;
let companionStarted = false;
let companionLength = 0;
const companionChunks: Uint8Array[] = [];
try {
for await (const part of stream) {
if (part.type === "header") {View on GitHub (pinned to 3f1d897a7c)