paperclipai/paperclip · error

HEIF dimensions could not be verified

Error message

HEIF dimensions could not be verified

What it means

After walking all boxes, validateHeifDimensions checks that it saw an ftyp box with a recognized HEIF brand (heic/heix/hevc/hevx/mif1/msf1) and at least one ispe dimensions box. It throws when either is missing, meaning the bytes are not a verifiable HEIF file despite the declared content type — a guard against mislabeled or malformed containers reaching the native decoder.

Solutions

  1. Send correct bytes: re-encode the file as a genuine HEIF (heif-enc) or fix the client to declare the true content type (e.g. image/jpeg for a renamed JPEG).
  2. On the server, sniff magic bytes yourself before choosing the validation path: check for ftyp at offset 4 and map brands to the real type.
  3. Fall back to validatePhotonImage with the detected (not declared) content type.
  4. Reject with 415 Unsupported Media Type and a message asking the user to re-export the image.

Example fix

// before
await validatePhotonImage(body, 'image/heic'); // trust the header
// after
const realType = sniffImageType(body); // reads magic bytes
if (realType !== 'image/heic')
  return await validatePhotonImage(body, realType);
await validatePhotonImage(body, 'image/heic');
Defensive patterns

Strategy: validation

Validate before calling

export function looksLikeHeif(body: Buffer): boolean {
  if (body.length < 12 || body.toString('ascii', 4, 8) !== 'ftyp') return false;
  return /heic|heix|hevc|hevx|mif1|msf1/.test(body.toString('ascii', 8, Math.min(body.length, 40)));
}

Type guard

function isHeifMagic(body: Buffer): boolean {
  return body.length >= 12 && body.toString('ascii', 4, 8) === 'ftyp' &&
    /heic|heix|hevc|hevx|mif1|msf1/.test(body.toString('ascii', 8, 12));
}

Try / catch

try {
  await validatePhotonImage(body, declaredType);
} catch (err) {
  if (err instanceof Error && err.message === 'HEIF dimensions could not be verified') {
    const real = sniffImageType(body);
    if (real && real !== declaredType) return validatePhotonImage(body, real);
    return respond(415, 'file is not a valid HEIF image');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling validatePhotonImage/photonHeifPreview with HEIF content types on a body that lacks an ftyp box with a HEIC/HEIF brand, or has no ispe boxes (e.g. a JPEG renamed to .heic, a bare ISO-BMFF container without image spatial extents, or encrypted/drm HEIF).

Common situations: Clients setting Content-Type: image/heic based on file extension alone; Apple .heic files with unusual brand sets; renamed JPEG/PNG files; minimal HEIF containers that carry metadata but no image spatial extents.

Related errors


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

Appendix: source

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

          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,
  contentType: string,
): Promise<void> {
  if (!contentType.startsWith("image/")) return;
  if (HEIF_CONTENT_TYPES.has(contentType)) return validateHeifDimensions(body);
  const metadata = await sharp(body, {
    limitInputPixels: MAX_PIXELS,
    failOn: "error",
  }).metadata();
  if (
    !metadata.width ||
    !metadata.height ||
    metadata.width * metadata.height * (metadata.pages ?? 1) > MAX_PIXELS
  )
    throw new Error("Decoded image exceeds the pixel limit");

View on GitHub (pinned to 3f1d897a7c)