{"record":{"id":"a97a52191afe10ba","repo":"paperclipai/paperclip","slug":"heif-exceeds-the-attachment-byte-limit","errorCode":null,"errorMessage":"HEIF exceeds the attachment byte limit","messagePattern":"HEIF exceeds the attachment byte limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/photon/media.ts","lineNumber":67,"sourceCode":"        if (\n          !width ||\n          !height ||\n          width > 16_384 ||\n          height > 16_384 ||\n          width * height > MAX_PIXELS\n        )\n          throw new Error(\"HEIF decoded image exceeds the pixel limit\");\n        totalPixels += width * height;\n        if (totalPixels > MAX_PIXELS * 3 || ++dimensions > 512)\n          throw new Error(\"HEIF image collection exceeds the pixel limit\");\n      } else if ([\"meta\", \"iprp\", \"ipco\"].includes(type)) {\n        visit(content + (type === \"meta\" ? 4 : 0), at + size, depth + 1);\n      }\n      at += size;\n    }\n  };\n  if (!body.length || body.length > MAX_ATTACHMENT_BYTES)\n    throw new Error(\"HEIF exceeds the attachment byte limit\");\n  visit(0, body.length, 0);\n  if (!branded || !dimensions)\n    throw new Error(\"HEIF dimensions could not be verified\");\n}\n\nexport async function validatePhotonImage(\n  body: Buffer,\n  contentType: string,\n): Promise<void> {\n  if (!contentType.startsWith(\"image/\")) return;\n  if (HEIF_CONTENT_TYPES.has(contentType)) return validateHeifDimensions(body);\n  const metadata = await sharp(body, {\n    limitInputPixels: MAX_PIXELS,\n    failOn: \"error\",\n  }).metadata();\n  if (\n    !metadata.width ||\n    !metadata.height ||","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/photon/media.ts#L49-L85","documentation":"validateHeifDimensions first checks that the body is non-empty and not larger than MAX_ATTACHMENT_BYTES before parsing any boxes. It throws when the HEIF payload is zero-length or exceeds the configured attachment byte cap, so oversized files are rejected before any structure parsing or native decoding.","triggerScenarios":"Calling validatePhotonImage with a HEIF content type and a Buffer that is empty (0 bytes) or whose length exceeds MAX_ATTACHMENT_BYTES (from server/src/attachment-types.js).","commonSituations":"Failed client uploads producing empty buffers (truncated request bodies, wrong Content-Length); users attaching 100MB+ HEIC video-like sequences; proxy/gateway limits stripping bodies.","solutions":["Check body.length in the caller and return a 413 Payload Too Large with the allowed size before invoking validation.","Configure or verify MAX_ATTACHMENT_BYTES in attachment-types.js to match your gateway's body-size limits (e.g. express.json({limit})).","Fix the upload path producing empty buffers — verify the client actually streamed the bytes and Content-Length matches.","Compress/resize the HEIC client-side (e.g. sips -s formatOptions 50%) to fit under the byte cap."],"exampleFix":"// before\nrouter.post('/attachments', async (req, res) => {\n  await validatePhotonImage(req.body, req.headers['content-type']);\n});\n// after\nrouter.post('/attachments', async (req, res) => {\n  if (!req.body?.length || req.body.length > MAX_ATTACHMENT_BYTES)\n    return res.status(413).json({ error: 'attachment too large or empty' });\n  await validatePhotonImage(req.body, req.headers['content-type']);\n});","handlingStrategy":"validation","validationCode":"import { MAX_ATTACHMENT_BYTES } from './attachment-types.js';\nexport function isAttachmentWithinByteLimit(body?: Buffer | null): boolean {\n  return !!body && body.length > 0 && body.length <= MAX_ATTACHMENT_BYTES;\n}","typeGuard":"function hasBytes(body: Buffer | undefined | null): body is Buffer {\n  return Buffer.isBuffer(body) && body.length > 0;\n}","tryCatchPattern":"try {\n  await validatePhotonImage(body, contentType);\n} catch (err) {\n  if (err instanceof Error && err.message === 'HEIF exceeds the attachment byte limit') {\n    return respond(413, `attachment must be between 1 byte and ${MAX_ATTACHMENT_BYTES} bytes`);\n  }\n  throw err;\n}","preventionTips":["Check Content-Length against the byte cap before reading the full body","Configure express/fastify body limits to MAX_ATTACHMENT_BYTES so oversized uploads never reach validation","Verify upload completion client-side (byte count sent vs file size)","Guard against empty buffers from failed multipart reads before calling validators"],"tags":["image","heif","attachment-size","payload-too-large"],"backgroundTag":"payload-too-large","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}