{"record":{"id":"eb56679e5d8ea26e","repo":"mozilla/pdf.js","slug":"required-hhea-table-is-not-found","errorCode":null,"errorMessage":"Required \"hhea\" table is not found","messagePattern":"Required \"hhea\" table is not found","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"error","filePath":"src/core/fonts.js","lineNumber":2987,"sourceCode":"        tables.loca,\n        tables.glyf,\n        numGlyphs,\n        isGlyphLocationsLong,\n        hintsValid,\n        dupFirstEntry,\n        maxSizeOfInstructions\n      );\n      missingGlyphs = glyphsInfo.missingGlyphs;\n\n      // Some fonts have incorrect maxSizeOfInstructions values, so we use\n      // the computed value instead.\n      if (version >= 0x00010000 && tables.maxp.length >= 32) {\n        tables.maxp.data[26] = glyphsInfo.maxSizeOfInstructions >> 8;\n        tables.maxp.data[27] = glyphsInfo.maxSizeOfInstructions & 255;\n      }\n    }\n    if (!tables.hhea) {\n      throw new FormatError('Required \"hhea\" table is not found');\n    }\n\n    // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth\n    // Sometimes it's 0. That needs to be fixed\n    if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) {\n      tables.hhea.data[10] = 0xff;\n      tables.hhea.data[11] = 0xff;\n    }\n\n    // Extract some more font properties from the OpenType head and\n    // hhea tables; yMin and descent value are always negative.\n    const metricsOverride = {\n      unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),\n      yMax: signedInt16(tables.head.data[42], tables.head.data[43]),\n      yMin: signedInt16(tables.head.data[38], tables.head.data[39]),\n      ascent: signedInt16(tables.hhea.data[4], tables.hhea.data[5]),\n      descent: signedInt16(tables.hhea.data[6], tables.hhea.data[7]),\n      lineGap: signedInt16(tables.hhea.data[8], tables.hhea.data[9]),","sourceCodeStart":2969,"sourceCodeEnd":3005,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/fonts.js#L2969-L3005","documentation":"Thrown when the font's table directory lacks an 'hhea' (Horizontal Header) table. The hhea table is mandatory — it carries ascent, descent, lineGap, maxAdvanceWidth, and the numberOfHMetrics used by the hmtx table. Without it, horizontal metrics cannot be parsed and the font's vertical layout is undefined.","triggerScenarios":"After the TrueType glyph location sanitization block (or after the CFF path rejoins), the check if (!tables.hhea) at line 2986 throws. Note that sanitizeMetrics was already called with tables.hhea earlier (it handles a null hhea gracefully), but subsequent code at line 2992 reads tables.hhea.data directly.","commonSituations":"A corrupt font missing the hhea table due to truncation or stripping. Fonts produced by defective subsetting tools that dropped hhea. Non-standard fonts that only provide vertical metrics (vhea) without horizontal. Damaged embedded font streams in PDFs.","solutions":["Replace the font with a complete copy that includes the hhea table.","Rebuild the font with fonttools to regenerate the hhea table from glyph metrics.","Validate with ots-sanitize — it flags missing hhea as a critical error.","If subsetting fonts, use a reliable tool (pyftsubset) that preserves mandatory tables."],"exampleFix":"# rebuild font to ensure hhea is present and valid\nfrom fontTools import ttLib\nfont = ttLib.TTFont('broken.ttf')\nhhea = font['hhea']  # fontTools rebuilds on save if missing/corrupt\nfont.save('fixed.ttf')\nots-sanitize fixed.ttf","handlingStrategy":"validation","validationCode":"// Server-side: verify font has hhea table\n// from fontTools import ttLib\n// font = ttLib.TTFont('font.ttf')\n// assert 'hhea' in font, 'Font missing hhea table'\n","typeGuard":null,"tryCatchPattern":"try {\n  await page.render(renderParams).promise;\n} catch (err) {\n  if (err.message?.includes('Required \"hhea\" table is not found')) {\n    console.error('Font missing hhea table; replace embedded font.');\n  } else { throw err; }\n}","preventionTips":["Ensure all fonts include the mandatory hhea table before embedding.","Rebuild fonts with fonttools to regenerate missing horizontal metrics tables.","Use pyftsubset for subsetting — it preserves mandatory tables including hhea."],"tags":["font","hhea-table","required-table","font-metrics","truetype","opentype","format-error"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}