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
- 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.
- Re-save the PDF through Ghostscript (gs -sDEVICE=pdfwrite) to re-embed or repair the font.
- If you control the source, re-embed the font correctly with a valid CFF program.
- 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
- Pre-validate embedded fonts with fontTools (ttx) before shipping PDFs.
- Re-embed fonts through Ghostscript to repair corrupt CFF programs.
- Keep pdf.js up to date; later versions add more font-repair fallbacks.
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
- CFF Private DICT extends past end of font
- Unknown charset format
- Unknown encoding format: ${format} in CFF
- parseFDSelect: Unknown format "${format}".
- parseFDSelect: Invalid font data.
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/9ef46c50ce9c04d5.
Report an issue: GitHub.