mozilla/pdf.js · error · FormatError

bad ObjStm stream

Error message

bad ObjStm stream

What it means

A FormatError raised in XRef.fetchCompressed when the object referenced by a compressed xref entry does not resolve to a BaseStream. Object Streams (ObjStm) must be streams; if the fetch returns a plain dict, null, or a primitive, the compressed object cannot be decoded. It indicates the xref entry's offset points at the wrong object or the object stream itself is malformed.

Source

Thrown at src/core/xref.js:961

        ? parser.getObj(this.encrypt.createCipherTransform(num, gen))
        : parser.getObj();
    if (!(xrefEntry instanceof BaseStream)) {
      if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
        assert(
          xrefEntry !== undefined,
          'fetchUncompressed: The "xrefEntry" cannot be undefined.'
        );
      }
      this.#cacheMap.set(num, xrefEntry);
    }
    return xrefEntry;
  }

  fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
    const tableOffset = xrefEntry.offset;
    const stream = this.fetch(Ref.get(tableOffset, 0));
    if (!(stream instanceof BaseStream)) {
      throw new FormatError("bad ObjStm stream");
    }
    const first = stream.dict.get("First");
    const n = stream.dict.get("N");
    if (!Number.isInteger(first) || !Number.isInteger(n)) {
      throw new FormatError("invalid first and n parameters for ObjStm stream");
    }
    let parser = new Parser({
      lexer: new Lexer(stream),
      xref: this,
      allowStreams: true,
    });
    const nums = new Array(n);
    const offsets = new Array(n);
    // read the object numbers to populate cache
    for (let i = 0; i < n; ++i) {
      const num = parser.getObj();
      if (!Number.isInteger(num)) {
        throw new FormatError(

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Validate the file with qpdf --check or mutool clean to detect/repair object stream corruption.
  2. Re-export the PDF from its source application.
  3. Catch FormatError around page access and skip the affected page rather than failing the whole document.
  4. If generating PDFs yourself, ensure ObjStm objects are emitted as streams with correct /Type /ObjStm.

Example fix

// before
const page = await doc.getPage(n);
const content = await page.getTextContent(); // throws FormatError

// after
try {
  const page = await doc.getPage(n);
  const content = await page.getTextContent();
} catch (e) {
  if (e instanceof pdfjsLib.FormatError) {
  console.warn(`Page ${n} skipped: corrupt object stream`, e.message);
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const obj = await doc.getPage(n);
} catch (e) {
  if (e instanceof pdfjsLib.FormatError) {
    console.warn(`Skipping object/page ${n}: corrupt ObjStm`);
    continue;
  }
  throw e;
}

Prevention

When it happens

Trigger: A compressed xref table entry whose offset field references an object number that is not an ObjStm; a cross-reference where the generator object was overwritten/corrupted; encrypted ObjStm decrypted to a non-stream; manual xref edits that point at the wrong object.

Common situations: PDFs produced by buggy/minimal writers; files repaired by tools that rewrote the xref incorrectly; files damaged in transit that still have a readable trailer but a broken object stream.

Related errors


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