mozilla/pdf.js · error · FormatError

Node must be a dictionary.

Error message

Node must be a dictionary.

What it means

Thrown in Catalog.getPageIndex() (catalog.js:1612) during the upward Parent-chain walk when a fetched node is not null but is not a Dict. Each node on the chain (Page, then successive Parents) must be a dictionary; a non-dict, non-null node breaks the traversal.

Source

Thrown at src/core/catalog.js:1612

    const visited = new RefSet();
    visited.put(pageRef);

    while (true) {
      const node = await xref.fetchAsync(ref);
      if (
        isRefsEqual(ref, pageRef) &&
        !isDict(node, "Page") &&
        !(node instanceof Dict && !node.has("Type") && node.has("Contents"))
      ) {
        throw new FormatError(
          "The reference does not point to a /Page dictionary."
        );
      }
      if (!node) {
        break;
      }
      if (!(node instanceof Dict)) {
        throw new FormatError("Node must be a dictionary.");
      }
      const parentRef = node.getRaw("Parent");
      if (parentRef instanceof Ref) {
        if (visited.has(parentRef)) {
          throw new FormatError("Pages tree contains circular reference.");
        }
        visited.put(parentRef);
      }

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

      const kids = await parent.getAsync("Kids");

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Repair the PDF with qpdf/mutool to rebuild the /Parent chain.
  2. Run 'qpdf --check' to detect dangling/wrong /Parent references.
  3. Catch the FormatError around getPageIndex and treat the index as unresolvable.
  4. When producing PDFs, ensure every /Parent points to a real /Pages dictionary.
Defensive patterns

Strategy: try-catch

Validate before calling

// The parent chain is internal; pre-validation means repairing the PDF.
// qpdf --check in.pdf   (reports dangling /Parent refs)
// mutool clean in.pdf out.pdf

Try / catch

try {
  const idx = await pdf.getPageIndex(ref);
} catch (err) {
  if (/Node must be a dictionary/i.test(err?.message)) {
    console.warn('Corrupt /Parent chain; repair the PDF', err);
  } else throw err;
}

Prevention

When it happens

Trigger: getPageIndex walks ref -> Parent -> Parent...; xref.fetchAsync(ref) returns a truthy non-Dict (stream, array, scalar). Reached after the initial /Page check passed but a parent node resolved to the wrong type, typically due to a corrupt xref or malformed /Parent reference.

Common situations: A corrupt /Parent indirect reference resolving to a non-dictionary; a shifted xref pointing /Parent at the wrong object; an edited PDF with a broken parent chain.

Related errors


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