{"record":{"id":"d042f3bf9e83f511","repo":"mozilla/pdf.js","slug":"cff-private-dict-extends-past-end-of-font","errorCode":null,"errorMessage":"CFF Private DICT extends past end of font","messagePattern":"CFF Private DICT extends past end of font","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"error","filePath":"src/core/cff_parser.js","lineNumber":831,"sourceCode":"    }\n    const privateOffset = parentDict.getByName(\"Private\");\n    // make sure the params are formatted correctly\n    if (!Array.isArray(privateOffset) || privateOffset.length !== 2) {\n      parentDict.removeByName(\"Private\");\n      return;\n    }\n    const size = privateOffset[0];\n    const offset = privateOffset[1];\n    // remove empty dicts or ones that refer to invalid location\n    if (size === 0 || offset >= this.bytes.length) {\n      this.emptyPrivateDictionary(parentDict);\n      return;\n    }\n    // The Private DICT extends past the end of the font data, which means\n    // the embedded font is truncated; abort so the caller can substitute a\n    // system font instead of rendering blank glyphs (issue 7625).\n    if (offset + size > this.bytes.length) {\n      throw new FormatError(\"CFF Private DICT extends past end of font\");\n    }\n\n    const privateDictEnd = offset + size;\n    const dictData = this.bytes.subarray(offset, privateDictEnd);\n    const dict = this.parseDict(dictData);\n    const privateDict = this.createDict(\n      CFFPrivateDict,\n      dict,\n      parentDict.strings\n    );\n    parentDict.privateDict = privateDict;\n\n    const blueScale = privateDict.getByName(\"BlueScale\");\n    const blueShift = privateDict.getByName(\"BlueShift\");\n    const blueFuzz = privateDict.getByName(\"BlueFuzz\");\n    const expansionFactor = privateDict.getByName(\"ExpansionFactor\");\n    if (\n      blueScale === 0 &&","sourceCodeStart":813,"sourceCodeEnd":849,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/cff_parser.js#L813-L849","documentation":"Thrown by CFFParser.parsePrivateDict when the Private DICT's offset+size exceeds the total font byte length, i.e. the embedded CFF font is truncated. Deliberately added (issue 7625) so the caller aborts and substitutes a system font rather than rendering blank glyphs.","triggerScenarios":"An embedded CFF font declares a Private DICT whose [size, offset] pair points past the end of the available font bytes. Reached only after earlier guards pass (size != 0 and offset < bytes.length), specifically when `offset + size > this.bytes.length`.","commonSituations":"PDFs with truncated or partially downloaded embedded CFF fonts; font streams cut off by storage limits; corrupt files where the Private DICT pointer is stale; output from faulty font subsetting/embedding tools.","solutions":["Accept pdf.js's automatic fallback to a system font (this error is designed to trigger that).","Re-embed or repair the font by re-saving the PDF with Ghostscript or fontTools.","Ensure the source font file is complete before subsetting/embedding in your pipeline.","If streaming the PDF over range requests, verify the full font stream was fetched before parsing."],"exampleFix":"// No caller-side fix; pdf.js substitutes a fallback font.\n// To prevent: validate the CFF before embedding.\ntry {\n  await page.render({ canvasContext, viewport }).promise;\n} catch (e) {\n  console.warn('Render aborted; embedded CFF font is truncated:', e);\n}","handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  await page.render({ canvasContext, viewport }).promise;\n} catch (e) {\n  // Truncated CFF Private DICT; pdf.js substitutes a system font.\n  console.warn('Truncated embedded CFF font:', e);\n}","preventionTips":["Ensure font streams are fully embedded (not cut off) when generating PDFs.","Verify range requests fetch the complete font stream before parsing.","Repair PDFs with Ghostscript to re-embed complete font programs."],"tags":["font","cff","cff-parser","corrupt-font","truncated","font-substitution"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}