mozilla/pdf.js · error · FormatError

Kid must be a reference.

Error message

Kid must be a reference.

What it means

Thrown by Catalog.getPageIndex() while iterating a parent's /Kids array. An element of that array is not an indirect object reference (Ref). The PDF spec requires /Kids to contain only indirect references; direct inline values violate the structure and cannot be counted.

Source

Thrown at src/core/catalog.js:1642

        break;
      }
      if (!(parent instanceof Dict)) {
        throw new FormatError("Parent must be a dictionary.");
      }

      const kids = await parent.getAsync("Kids");
      if (!kids) {
        break;
      }
      if (!Array.isArray(kids)) {
        throw new FormatError("Kids must be an array.");
      }

      const kidPromises = [];
      let found = false;
      for (const kid of kids) {
        if (!(kid instanceof Ref)) {
          throw new FormatError("Kid must be a reference.");
        }
        if (isRefsEqual(kid, ref)) {
          found = true;
          break;
        }
        kidPromises.push(
          xref.fetchAsync(kid).then(obj => {
            if (!(obj instanceof Dict)) {
              throw new FormatError("Kid node must be a dictionary.");
            }
            if (obj.has("Count")) {
              const count = obj.get("Count");
              if (Number.isInteger(count) && count >= 0) {
                total += count;
                return;
              }
              throw new FormatError("Count must be a (positive) integer.");
            }

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Catch the error from getPageIndex and fall back to a linear getPage scan.
  2. Repair the file with Ghostscript or qpdf so all /Kids entries become indirect references.
  3. Regenerate the PDF with a spec-compliant library.

Example fix

// before
const pageIndex = await pdfDocument.getPageIndex(pageRef);

// after
let pageIndex = -1;
try {
  pageIndex = await pdfDocument.getPageIndex(pageRef);
} catch (e) {
  for (let i = 0; i < pdfDocument.numPages; i++) {
    const page = await pdfDocument.getPage(i);
    if (page.ref && page.ref.num === pageRef.num) { pageIndex = i; break; }
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  idx = await pdfDocument.getPageIndex(ref);
} catch (e) {
  for (let i = 0; i < pdfDocument.numPages; i++) {
    const p = await pdfDocument.getPage(i);
    if (p.ref && p.ref.num === ref.num) { idx = i; break; }
  }
}

Prevention

When it happens

Trigger: A parent /Pages node whose /Kids array contains a direct dictionary, number, string, or null instead of a Ref object. Triggered during the per-kid loop: `for (const kid of kids) { if (!(kid instanceof Ref)) throw ... }`.

Common situations: PDF authors who inline page dictionaries directly into /Kids rather than via indirect references; corrupt xref tables that turned references into direct objects; output from non-compliant converters.

Related errors


AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13). Data as JSON: /api/errors/98b20d1af007841f. Report an issue: GitHub.