mozilla/pdf.js · error · FormatError
There must be a private dictionary.
Error message
There must be a private dictionary.
What it means
Thrown by CFFCompiler.compilePrivateDicts when iterating Font DICTs (the FDArray of a CIDFont) and encountering one that lacks either a privateDict or a 'Private' name. Every Font DICT must carry a Private DICT for compilation to succeed; its absence means the in-memory CFF object is inconsistent.
Source
Thrown at src/core/cff_parser.js:1752
const fontDictTracker = new CFFOffsetTracker();
const fontDictData = this.compileDict(fontDict, fontDictTracker);
fontDictTrackers.push(fontDictTracker);
fdArrayIndex.add(fontDictData);
fontDictTracker.offset(length);
}
fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
return {
trackers: fontDictTrackers,
output: fdArrayIndex,
};
}
compilePrivateDicts(dicts, trackers, output) {
for (let i = 0, ii = dicts.length; i < ii; ++i) {
const fontDict = dicts[i];
const privateDict = fontDict.privateDict;
if (!privateDict || !fontDict.hasName("Private")) {
throw new FormatError("There must be a private dictionary.");
}
const privateDictTracker = new CFFOffsetTracker();
const privateDictData = this.compileDict(privateDict, privateDictTracker);
let outputLength = output.length;
privateDictTracker.offset(outputLength);
if (!privateDictData.length) {
// The private dictionary was empty, set the output length to zero to
// ensure the offset length isn't out of bounds in the eyes of the
// sanitizer.
outputLength = 0;
}
trackers[i].setEntryLocation(
"Private",
[privateDictData.length, outputLength],
output
);View on GitHub (pinned to 5903d58d58)
Solutions
- Report to pdf.js with the offending CIDFont — emptyPrivateDictionary should normally prevent this.
- Ensure any code that builds/modifies Font DICTs always attaches a Private DICT and sets the 'Private' name.
- Repair the source font with fontTools before embedding.
Example fix
// before (internal: Font DICT missing Private)
this.compilePrivateDicts(dicts, trackers, output); // throws
// after (ensure every Font DICT has a Private DICT before compiling)
for (const fd of dicts) {
if (!fd.privateDict || !fd.hasName('Private')) {
this.emptyPrivateDictionary(fd); // attach an empty Private DICT
}
}
this.compilePrivateDicts(dicts, trackers, output); Defensive patterns
Strategy: validation
Validate before calling
// Ensure every Font DICT has a Private DICT before compiling.
function ensurePrivateDicts(parser, dicts) {
for (const fd of dicts) {
if (!fd.privateDict || !fd.hasName('Private')) {
parser.emptyPrivateDictionary(fd);
}
}
} Type guard
function fontDictHasPrivate(fd) {
return !!fd.privateDict && fd.hasName('Private');
} Try / catch
try {
this.compilePrivateDicts(dicts, trackers, output);
} catch (e) {
// A Font DICT lacks Private; attach empty ones and retry.
for (const fd of dicts) {
if (!fd.privateDict || !fd.hasName('Private')) this.emptyPrivateDictionary(fd);
}
this.compilePrivateDicts(dicts, trackers, output);
} Prevention
- Always attach a Private DICT (even if empty) when constructing Font DICTs.
- Run emptyPrivateDictionary as a safety pass before compilePrivateDicts.
- Report unexpected occurrences to pdf.js with the offending CIDFont.
When it happens
Trigger: Compiling a CIDFont whose FDArray contains a Font DICT without an attached privateDict or without the 'Private' operator name. Reached during the per-dict loop in compilePrivateDicts, used when re-emitting a sanitized CFF font.
Common situations: A malformed CIDFont where parsePrivateDict fell back to emptyPrivateDictionary but the 'Private' name was later removed; a pdf.js internal bug in FDArray construction; corrupt font data that yields Font DICTs missing Private entries.
Related errors
- Already tracking location of ${key}
- Not tracking location of ${key}
- writing to an offset that is not empty
- Unknown data type of ${type}
- Invalid dictionary name "${name}"
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/0b0254a4ff869c9a.
Report an issue: GitHub.