mozilla/pdf.js · critical · InvalidPDFException

Invalid PDF structure.

Error message

Invalid PDF structure.

What it means

Thrown as an InvalidPDFException after pdf.js exhausts every recovery path while trying to find the document's trailer/Catalog. The loop in XRef#findTrailerDict scans all parsed xref entries for any dictionary containing a /Root key; if none qualifies, the PDF has no discoverable Catalog and cannot be opened. This is the terminal failure for documents whose cross-reference tables and trailers are unrecoverably damaged.

Source

Thrown at src/core/xref.js:729

        const ref = Ref.get(parseInt(num, 10), entry.gen);
        let obj;

        try {
          obj = this.fetch(ref);
        } catch {
          continue;
        }
        if (obj instanceof BaseStream) {
          obj = obj.dict;
        }
        if (obj instanceof Dict && obj.has("Root")) {
          return obj;
        }
      }
    }

    // nothing helps
    throw new InvalidPDFException("Invalid PDF structure.");
  }

  readXRef(recoveryMode = false) {
    const stream = this.stream;
    // Keep track of already parsed XRef tables, to prevent an infinite loop
    // when parsing corrupt PDF files where e.g. the /Prev entries create a
    // circular dependency between tables (fixes bug1393476.pdf).
    const startXRefParsedCache = new Set();

    while (this.startXRefQueue.length) {
      try {
        const startXRef = this.startXRefQueue[0];

        if (startXRefParsedCache.has(startXRef)) {
          warn("readXRef - skipping XRef table since it was already parsed.");
          this.startXRefQueue.shift();
          continue;
        }

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Open the file in a desktop PDF reader to confirm it is actually a valid PDF; if other readers also fail, the file is corrupt and cannot be processed.
  2. Verify the byte stream you pass to getDocument is the raw PDF bytes (check it starts with %PDF- and ends with %%EOF) and not a wrapped/error response.
  3. Re-fetch or re-export the source PDF from its origin to obtain a non-truncated copy.
  4. If you control generation, regenerate the PDF (the writer emitted a broken xref/trailer).
  5. As a last resort, attempt repair with an external tool (qpdf --check, ghostscript) then re-load.

Example fix

// before
const task = pdfjsLib.getDocument({ url });
const doc = await task.promise; // throws InvalidPDFException

// after
const buf = await (await fetch(url)).arrayBuffer();
const bytes = new Uint8Array(buf);
const head = String.fromCharCode(...bytes.subarray(0, 5));
if (head !== '%PDF-') {
  throw new Error('File is not a PDF (missing %PDF- header)');
}
const task = pdfjsLib.getDocument({ data: bytes });
try {
  const doc = await task.promise;
} catch (e) {
  if (e instanceof pdfjsLib.InvalidPDFException) {
    // surface a user-friendly 'corrupt file' message
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the bytes look like a PDF before loading.
function looksLikePdf(bytes) {
  const head = String.fromCharCode(...bytes.subarray(0, 5));
  const tail = String.fromCharCode(...bytes.subarray(bytes.length - 6));
  return head === '%PDF-' && tail.includes('%%EOF');
}

const bytes = new Uint8Array(await (await fetch(url)).arrayBuffer());
if (!looksLikePdf(bytes)) throw new Error('Not a valid PDF file');

Try / catch

try {
  const doc = await loadingTask.promise;
} catch (e) {
  if (e instanceof pdfjsLib.InvalidPDFException) {
    // show user 'This file is not a valid PDF' and stop.
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: A PDF whose xref table, xref stream, and trailer are all missing or unreadable AND no object in the file can be fetched as a dictionary containing /Root. Typically reached when startxRef points nowhere, the trailer lacks /Root, and the fallback scan in XRef fails. Also hit when the file is not actually a PDF (e.g. HTML/JSON served with wrong MIME) yet partially tokenized.

Common situations: Serving a truncated or zero-byte download; a download that saved an HTML error page with a .pdf extension; PDFs corrupted by transfer/storage; encrypted-with-broken-trailer files; user-uploaded content that failed validation upstream.

Related errors


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