{"record":{"id":"cf4748c9286c71a2","repo":"mozilla/pdf.js","slug":"descendant-font-is-not-a-dictionary","errorCode":null,"errorMessage":"Descendant font is not a dictionary.","messagePattern":"Descendant font is not a dictionary\\.","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"error","filePath":"src/core/evaluator.js","lineNumber":4309,"sourceCode":"    if (!(type instanceof Name)) {\n      throw new FormatError(\"invalid font Subtype\");\n    }\n\n    let composite = false;\n    let hash;\n    if (type.name === \"Type0\") {\n      // If font is a composite\n      //  - get the descendant font\n      //  - set the type according to the descendant font\n      //  - get the FontDescriptor from the descendant font\n      const df = dict.get(\"DescendantFonts\");\n      if (!df) {\n        throw new FormatError(\"Descendant fonts are not specified\");\n      }\n      dict = Array.isArray(df) ? this.xref.fetchIfRef(df[0]) : df;\n\n      if (!(dict instanceof Dict)) {\n        throw new FormatError(\"Descendant font is not a dictionary.\");\n      }\n      type = dict.get(\"Subtype\");\n      if (!(type instanceof Name)) {\n        throw new FormatError(\"invalid font Subtype\");\n      }\n      composite = true;\n    }\n\n    let firstChar = dict.get(\"FirstChar\");\n    if (!Number.isInteger(firstChar)) {\n      firstChar = 0;\n    }\n    let lastChar = dict.get(\"LastChar\");\n    if (!Number.isInteger(lastChar)) {\n      lastChar = composite ? 0xffff : 0xff;\n    }\n    const descriptor = dict.get(\"FontDescriptor\");\n    const toUnicode = dict.get(\"ToUnicode\") || baseDict.get(\"ToUnicode\");","sourceCodeStart":4291,"sourceCodeEnd":4327,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/evaluator.js#L4291-L4327","documentation":"Thrown by preEvaluateFont() when a Type0 font's /DescendantFonts[0], after indirect-reference resolution, is not a Dictionary. The descendant must be a CIDFont dictionary carrying /Subtype, /CIDSystemInfo, /FontDescriptor, etc.; a non-dict value means the reference is broken or the producer wrote the wrong object. This guard protects the subsequent .get('Subtype') call.","triggerScenarios":"A Type0 font whose /DescendantFonts array's first element resolves (via xref.fetchIfRef) to a primitive, null, stream, or dangling reference. Fires in preEvaluateFont() during font load for the relevant page.","commonSituations":"Dangling indirect references from broken cross-reference tables, PDFs edited by hand or by tools that did not preserve object graphs, or files corrupted during transfer/storage. Also possible after a faulty PDF/A conversion that stripped CIDFont dictionaries.","solutions":["Run qpdf --check to detect broken xrefs, then qpdf --linearize to rebuild the object graph.","Re-export the source document to PDF using a different producer (Acrobat, Ghostscript, libreoffice).","Catch per-page and degrade rendering rather than aborting the document.","If you control the producer, ensure /DescendantFonts entries are indirect refs that resolve to CIDFont dicts."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await page.render({ canvasContext, viewport });\n} catch (e) {\n  if (e.name === 'FormatError' && /Descendant font is not a dictionary/.test(e.message)) {\n    // dangling xref — skip page or use fallback font\n  } else throw e;\n}","preventionTips":["Run qpdf --check to detect broken cross-reference tables before processing.","Repair xrefs with qpdf --linearize or Ghostscript before rendering.","When authoring, ensure /DescendantFonts entries resolve to CIDFont dictionaries."],"tags":["pdf","font","type0","descendant-fonts","xref","format-error"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}