{"record":{"id":"535e83aef03e284e","repo":"mozilla/pdf.js","slug":"fontfile-should-be-a-stream","errorCode":null,"errorMessage":"FontFile should be a stream","messagePattern":"FontFile should be a stream","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"warning","filePath":"src/core/evaluator.js","lineNumber":4620,"sourceCode":"    }\n\n    if (!(fontName instanceof Name)) {\n      throw new FormatError(\"invalid font name\");\n    }\n\n    let fontFile, fontFileN, subtype, length1, length2, length3;\n    try {\n      for (const n of [\"FontFile\", \"FontFile2\", \"FontFile3\"]) {\n        fontFile = descriptor.get(n);\n        if (fontFile) {\n          fontFileN = n;\n          break;\n        }\n      }\n\n      if (fontFile) {\n        if (!(fontFile instanceof BaseStream)) {\n          throw new FormatError(\"FontFile should be a stream\");\n        } else {\n          if (fontFile.isAsync) {\n            const bytes = await fontFile.asyncGetBytes();\n            if (bytes) {\n              fontFile = new Stream(bytes, 0, bytes.length, fontFile.dict);\n            }\n          }\n          if (fontFile.isEmpty) {\n            throw new FormatError(\"FontFile is empty\");\n          }\n        }\n      }\n    } catch (ex) {\n      if (!this.options.ignoreErrors) {\n        throw ex;\n      }\n      warn(`translateFont - fetching \"${fontName.name}\" font file: \"${ex}\".`);\n      fontFile = null;","sourceCodeStart":4602,"sourceCodeEnd":4638,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/evaluator.js#L4602-L4638","documentation":"Thrown inside translateFont() when a font descriptor's /FontFile, /FontFile2, or /FontFile3 entry exists but is not a BaseStream (i.e. not a PDF stream object). Embedded font programs must be stream objects carrying the raw font bytes; a non-stream value means the reference is broken. The guard wraps the entire font-file fetch in a try/catch that honors options.ignoreErrors, so with the default render path it degrades to a warning and substitutes a fallback font.","triggerScenarios":"A /FontDescriptor whose /FontFile* entry resolves to a dictionary, number, string, null, or dangling reference instead of a stream. Fires during translateFont() when the descriptor declares an embedded font program that is not actually a stream.","commonSituations":"Font subsetting/embedding bugs in PDF generators, broken indirect references after linearization corruption, or PDFs where an optimizer replaced the font stream with a stub. Also seen when a FontFile3 references a sub-stream that was dropped during object-stream compression.","solutions":["Re-embed the font properly using the original source document and a conformant PDF exporter.","Run qpdf --object-streams=disable or Ghostscript to repair the object stream and stream references.","Rely on ignoreErrors (default) — PDF.js will warn and fall back to a standard font; rendering continues with substituted glyphs.","If authoring, validate that each /FontFile* entry is an indirect reference to a stream with /Length, /Subtype (for FontFile3), and byte payload."],"exampleFix":"// before\ngetDocument({ url, stopAtErrors: true }); // propagates the FormatError\n\n// after\ngetDocument({ url }); // ignoreErrors=true -> warn + fallback font, render continues","handlingStrategy":"validation","validationCode":"// This error is already gated by options.ignoreErrors inside translateFont().\n// Use the default render path (no stopAtErrors) to let PDF.js warn + fall back:\nconst pdf = await getDocument({ url }).promise;\n// Bad FontFile references degrade to a warn() and a fallback standard font.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Leave stopAtErrors at default (false) so corrupt FontFile refs warn instead of throw.","When authoring, ensure /FontFile* entries are indirect references to streams with /Length and byte payload.","Repair stream references with qpdf --object-streams=disable or Ghostscript."],"tags":["pdf","font","font-file","stream","format-error","ignore-errors"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}