paperclipai/paperclip · error

HEIF file type is missing

Error message

HEIF file type is missing

What it means

An ftyp (file type) box must carry at least a major brand (4 bytes) beyond its 8-byte header, i.e. size >= header + 8 (4 brand + typically minor version). If an ftyp box is smaller, the walker throws "HEIF file type is missing" because the HEIF brand information needed to confirm heic/heif compatibility cannot be read.

Solutions

  1. Reject the file — a valid HEIF always has a proper ftyp box; re-export from the source app.
  2. Verify with `ffprobe` or `file` that the file is genuinely HEIF/HEIC with readable brands.
  3. Re-encode to HEIC with sips/ImageMagick/libheif if the source is a convertible format.
  4. If malicious, keep blocked: the check gates downstream brand detection.

Example fix

// before: stub ftyp box (size 12)
// after: re-encode
magick input.png -quality 90 output.heic
Defensive patterns

Strategy: validation

Validate before calling

function hasProperFtyp(buf: Buffer): boolean {
  if (buf.length < 16 || buf.toString("ascii", 4, 8) !== "ftyp") return false;
  return buf.readUInt32BE(0) >= 16;
}

Type guard

function isBrandedHeif(b: Buffer): boolean {
  if (b.length < 16 || b.toString("ascii", 4, 8) !== "ftyp") return false;
  if (b.readUInt32BE(0) < 16) return false;
  return /heic|heix|hevc|hevx|mif1|msf1/.test(b.toString("ascii", 8, b.readUInt32BE(0)));
}

Try / catch

try {
  validateHeifDimensions(body);
} catch (e) {
  if (e instanceof Error && e.message === "HEIF file type is missing") {
    return rejectUpload("Not a valid HEIF file (missing brand data); re-export the image");
  }
  throw e;
}

Prevention

When it happens

Trigger: A buffer containing an ftyp box with size < 16 bytes (header 8 + fewer than 8 content bytes) encountered during validateHeifDimensions (media.ts:40-41).

Common situations: Hand-crafted or corrupted file with a stub ftyp; a container renamed to .heic that is not really HEIF; fuzzed input probing brand detection.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/e765c39f35bf850d. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/photon/media.ts:41

    for (let at = start; at < end; ) {
      if (++boxes > 4096 || end - at < 8)
        throw new Error("Invalid HEIF box structure");
      let size = body.readUInt32BE(at);
      const type = body.toString("ascii", at + 4, at + 8);
      let header = 8;
      if (size === 1) {
        if (end - at < 16) throw new Error("Invalid HEIF box length");
        const extended = body.readBigUInt64BE(at + 8);
        if (extended > BigInt(body.length))
          throw new Error("HEIF box exceeds file bounds");
        size = Number(extended);
        header = 16;
      } else if (size === 0) size = end - at;
      if (size < header || at + size > end)
        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");

View on GitHub (pinned to 3f1d897a7c)