paperclipai/paperclip · error
HEIF decoded image exceeds the pixel limit
Error message
HEIF decoded image exceeds the pixel limit
What it means
validateHeifDimensions walks the ISO-BMFF box structure of a HEIF file and reads each ispe (image spatial extents) box to get declared width/height before any native decoder runs. It throws this error when a single ispe box declares a zero dimension, a dimension above 16,384, or width*height above MAX_PIXELS (50,000,000). This is a decompression-bomb guard preventing huge allocations in the native HEIF converter.
Solutions
- Resize or re-export the image to at most 16,384x16,384 and under 50 megapixels (e.g. sips -Z 16384 or convert to JPEG) before uploading.
- If legitimate images are being rejected and the product allows it, raise MAX_PIXELS or the 16,384 per-dimension cap in server/src/services/photon/media.ts.
- Catch this specific Error message in ingestAttachments and reject the attachment with a clear user-facing 'image too large' error instead of a 500.
- Pre-probe client-side: read the HEIC's ispe/metadata in the browser or client and warn before upload.
Example fix
// before
const jpeg = await heifToJpeg(body, {quality:80});
// after
const metadata = await sharp(body, {limitInputPixels: MAX_PIXELS}).metadata();
if ((metadata.width ?? 0) * (metadata.height ?? 0) > MAX_PIXELS)
throw new Error("HEIF decoded image exceeds the pixel limit");
const jpeg = await heifToJpeg(body, {quality:80}); Defensive patterns
Strategy: validation
Validate before calling
import sharp from 'sharp';
export async function isHeifWithinPixelLimit(body: Buffer): Promise<boolean> {
if (!body.length) return false;
const meta = await sharp(body, { limitInputPixels: 50_000_000 }).metadata().catch(() => null);
if (!meta) return false; // HEIF: parse ispe boxes or pre-convert
const w = meta.width ?? 0, h = meta.height ?? 0;
return w > 0 && h > 0 && w <= 16_384 && h <= 16_384 && w * h <= 50_000_000;
} Type guard
function hasSafeHeifDimensions(d: { width?: number; height?: number }): boolean {
return typeof d.width === 'number' && typeof d.height === 'number' &&
d.width > 0 && d.height > 0 &&
d.width <= 16_384 && d.height <= 16_384 &&
d.width * d.height <= 50_000_000;
} Try / catch
try {
await validatePhotonImage(body, contentType);
} catch (err) {
if (err instanceof Error && err.message === 'HEIF decoded image exceeds the pixel limit') {
return respond(413, 'image resolution exceeds the 50MP limit');
}
throw err;
} Prevention
- Resize images client-side to <=16,384px per side before upload
- Enforce a pixel-count check in the browser using an ImageDecoder or pre-converted preview
- Warn users when ProRAW/panorama photos exceed 50MP
- Keep MAX_PIXELS limits aligned between client preview and server validation
When it happens
Trigger: Calling validatePhotonImage or photonHeifPreview with a body whose content type is image/heic, image/heif, image/heic-sequence, or image/heif-sequence, where any ispe box declares width or height of 0 or >16384, or a single image over 50MP.
Common situations: Users upload high-resolution iPhone panorama/ProRAW HEIC exports (e.g. 48MP+ photos) or mislabeled files whose ispe metadata exceeds limits; also crafted bomb files attempting decoder DoS.
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
- HEIF dimensions could not be verified
- HEIF image collection exceeds the pixel limit
- Attachment exceeds the configured size limit
- Decoded image exceeds the pixel limit
- HEIF exceeds the attachment byte limit
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/4be5e6d29cac1d60.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/photon/media.ts:56
throw new Error("HEIF box exceeds file bounds");
const content = at + header;
if (type === "ftyp") {
if (size < header + 8) throw new Error("HEIF file type is missing");
const brands = body.toString("ascii", content, at + size);
branded = /heic|heix|hevc|hevx|mif1|msf1/.test(brands);
} else if (type === "ispe") {
if (size !== header + 12)
throw new Error("Invalid HEIF image dimensions");
const width = body.readUInt32BE(content + 4);
const height = body.readUInt32BE(content + 8);
if (
!width ||
!height ||
width > 16_384 ||
height > 16_384 ||
width * height > MAX_PIXELS
)
throw new Error("HEIF decoded image exceeds the pixel limit");
totalPixels += width * height;
if (totalPixels > MAX_PIXELS * 3 || ++dimensions > 512)
throw new Error("HEIF image collection exceeds the pixel limit");
} else if (["meta", "iprp", "ipco"].includes(type)) {
visit(content + (type === "meta" ? 4 : 0), at + size, depth + 1);
}
at += size;
}
};
if (!body.length || body.length > MAX_ATTACHMENT_BYTES)
throw new Error("HEIF exceeds the attachment byte limit");
visit(0, body.length, 0);
if (!branded || !dimensions)
throw new Error("HEIF dimensions could not be verified");
}
export async function validatePhotonImage(
body: Buffer,View on GitHub (pinned to 3f1d897a7c)