mozilla/pdf.js · error · FormatError

Invalid CFF header

Error message

Invalid CFF header

What it means

Thrown by CFFParser.parseHeader while locating the CFF major-version byte (value 1). The parser scans the byte stream for a 1 and never finds one within bounds, meaning the data does not contain a valid CFF header. This indicates an empty, truncated, or non-CFF font stream.

Source

Thrown at src/core/cff_parser.js:394

    cff.charStrings = charStringsAndSeacs.charStrings;
    cff.seacs = charStringsAndSeacs.seacs;
    cff.widths = charStringsAndSeacs.widths;

    return cff;
  }

  parseHeader() {
    let bytes = this.bytes;
    const bytesLength = bytes.length;
    let offset = 0;

    // Prevent an infinite loop, by checking that the offset is within the
    // bounds of the bytes array. Necessary in empty, or invalid, font files.
    while (offset < bytesLength && bytes[offset] !== 1) {
      ++offset;
    }
    if (offset >= bytesLength) {
      throw new FormatError("Invalid CFF header");
    }
    if (offset !== 0) {
      info("cff data is shifted");
      bytes = bytes.subarray(offset);
      this.bytes = bytes;
    }
    const major = bytes[0];
    const minor = bytes[1];
    const hdrSize = bytes[2];
    const offSize = bytes[3];
    const header = new CFFHeader(major, minor, hdrSize, offSize);
    return { obj: header, endPos: hdrSize };
  }

  parseDict(dict) {
    const view = new DataView(dict.buffer, dict.byteOffset, dict.bytesLength);
    let pos = 0;

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Let pdf.js handle it: it catches the FormatError and substitutes a fallback system font, so usually no action is needed beyond accepting the substitution.
  2. Re-save the PDF through Ghostscript (gs -sDEVICE=pdfwrite) to re-embed or repair the font.
  3. If you control the source, re-embed the font correctly with a valid CFF program.
  4. If rendering must not degrade, pre-validate fonts with a tool like fontTools before embedding.

Example fix

// pdf.js recovers internally; callers just observe the render task promise.
const renderTask = page.render({ canvasContext, viewport });
try {
  await renderTask.promise;
} catch (e) {
  // Font failed to parse and could not be substituted; render is incomplete.
  console.warn('Render failed, possibly due to a corrupt embedded font:', e);
}
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

null

Try / catch

try {
  await page.render({ canvasContext, viewport }).promise;
} catch (e) {
  // CFF header invalid; pdf.js attempts system-font substitution.
  // If substitution also failed, the page is only partially rendered.
  console.warn('Font parse failure (invalid CFF header):', e);
}

Prevention

When it happens

Trigger: Parsing a font whose embedded CFF program has no byte equal to 1 (the required major version) — empty streams, random garbage, or a stream that is actually TrueType/glyf mislabeled as CFF. Triggered during font loading for any page using the affected font.

Common situations: Corrupt embedded fonts in downloaded PDFs; fonts damaged by partial file transfer; PDFs whose font streams were stripped to zero length by optimizing tools; CIDFont/CFF2 streams that fail the legacy major-version scan.

Related errors


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