{"record":{"id":"0b0254a4ff869c9a","repo":"mozilla/pdf.js","slug":"there-must-be-a-private-dictionary","errorCode":null,"errorMessage":"There must be a private dictionary.","messagePattern":"There must be a private dictionary\\.","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"error","filePath":"src/core/cff_parser.js","lineNumber":1752,"sourceCode":"      const fontDictTracker = new CFFOffsetTracker();\n      const fontDictData = this.compileDict(fontDict, fontDictTracker);\n      fontDictTrackers.push(fontDictTracker);\n      fdArrayIndex.add(fontDictData);\n      fontDictTracker.offset(length);\n    }\n    fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);\n    return {\n      trackers: fontDictTrackers,\n      output: fdArrayIndex,\n    };\n  }\n\n  compilePrivateDicts(dicts, trackers, output) {\n    for (let i = 0, ii = dicts.length; i < ii; ++i) {\n      const fontDict = dicts[i];\n      const privateDict = fontDict.privateDict;\n      if (!privateDict || !fontDict.hasName(\"Private\")) {\n        throw new FormatError(\"There must be a private dictionary.\");\n      }\n      const privateDictTracker = new CFFOffsetTracker();\n      const privateDictData = this.compileDict(privateDict, privateDictTracker);\n\n      let outputLength = output.length;\n      privateDictTracker.offset(outputLength);\n      if (!privateDictData.length) {\n        // The private dictionary was empty, set the output length to zero to\n        // ensure the offset length isn't out of bounds in the eyes of the\n        // sanitizer.\n        outputLength = 0;\n      }\n\n      trackers[i].setEntryLocation(\n        \"Private\",\n        [privateDictData.length, outputLength],\n        output\n      );","sourceCodeStart":1734,"sourceCodeEnd":1770,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/cff_parser.js#L1734-L1770","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (internal: Font DICT missing Private)\nthis.compilePrivateDicts(dicts, trackers, output); // throws\n\n// after (ensure every Font DICT has a Private DICT before compiling)\nfor (const fd of dicts) {\n  if (!fd.privateDict || !fd.hasName('Private')) {\n    this.emptyPrivateDictionary(fd); // attach an empty Private DICT\n  }\n}\nthis.compilePrivateDicts(dicts, trackers, output);","handlingStrategy":"validation","validationCode":"// Ensure every Font DICT has a Private DICT before compiling.\nfunction ensurePrivateDicts(parser, dicts) {\n  for (const fd of dicts) {\n    if (!fd.privateDict || !fd.hasName('Private')) {\n      parser.emptyPrivateDictionary(fd);\n    }\n  }\n}","typeGuard":"function fontDictHasPrivate(fd) {\n  return !!fd.privateDict && fd.hasName('Private');\n}","tryCatchPattern":"try {\n  this.compilePrivateDicts(dicts, trackers, output);\n} catch (e) {\n  // A Font DICT lacks Private; attach empty ones and retry.\n  for (const fd of dicts) {\n    if (!fd.privateDict || !fd.hasName('Private')) this.emptyPrivateDictionary(fd);\n  }\n  this.compilePrivateDicts(dicts, trackers, output);\n}","preventionTips":["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."],"tags":["font","cff","cff-compiler","cidfont","private-dict","internal-api","invariant"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}