{"record":{"id":"13c2c5e69d37eb16","repo":"mozilla/pdf.js","slug":"unicode-ranges-bits-123-are-reserved-for-interna","errorCode":null,"errorMessage":"Unicode ranges Bits > 123 are reserved for internal usage","messagePattern":"Unicode ranges Bits > 123 are reserved for internal usage","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"error","filePath":"src/core/fonts.js","lineNumber":838,"sourceCode":"      code |= 0;\n      if (firstCharIndex > code || !firstCharIndex) {\n        firstCharIndex = code;\n      }\n      if (lastCharIndex < code) {\n        lastCharIndex = code;\n      }\n\n      position = getUnicodeRangeFor(code, position);\n      if (position < 32) {\n        ulUnicodeRange1 |= 1 << position;\n      } else if (position < 64) {\n        ulUnicodeRange2 |= 1 << (position - 32);\n      } else if (position < 96) {\n        ulUnicodeRange3 |= 1 << (position - 64);\n      } else if (position < 123) {\n        ulUnicodeRange4 |= 1 << (position - 96);\n      } else {\n        throw new FormatError(\n          \"Unicode ranges Bits > 123 are reserved for internal usage\"\n        );\n      }\n    }\n    if (lastCharIndex > 0xffff) {\n      // OS2 only supports a 16 bit int. The spec says if supplementary\n      // characters are used the field should just be set to 0xFFFF.\n      lastCharIndex = 0xffff;\n    }\n  } else {\n    // TODO\n    firstCharIndex = 0;\n    lastCharIndex = 255;\n  }\n\n  const bbox = properties.bbox || [0, 0, 0, 0];\n  const unitsPerEm =\n    override.unitsPerEm ||","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/fonts.js#L820-L856","documentation":"Thrown while building the OS/2 ulUnicodeRange bitmask fields when getUnicodeRangeFor() returns a position >= 123. The OS/2 table has four 32-bit ulUnicodeRange fields (128 bits total), but only positions 0–122 are defined by the OpenType spec; positions 123–127 are reserved for internal usage and pdf.js refuses to set them.","triggerScenarios":"In createOS2Table(), iterating over charstrings entries, getUnicodeRangeFor(code, position) returns a value >= 123 for some character code. This means the font contains glyphs mapped to Unicode code points that fall into undefined OS/2 range groups.","commonSituations":"Fonts with very unusual or very-high Unicode code points (supplementary private-use areas, unassigned planes). Corrupt charstrings maps that include bogus code values. Custom or experimental fonts with private-use area characters beyond the defined ranges. Fonts processed by tools that generate invalid Unicode mappings.","solutions":["Inspect the font's charstrings/cmap with fonttools to identify glyphs mapped to unusual Unicode values and remove or remap them.","Rebuild the OS/2 table with fonttools after cleaning the cmap: font['OS/2'] = rebuilt; font.save('fixed.ttf').","If you control the font generation pipeline, filter out code points that map to undefined OS/2 Unicode ranges (positions >= 123).","Replace the problematic embedded font with a standard one."],"exampleFix":"# before — font has private-use glyphs in undefined ranges\nfrom fontTools import ttLib\nfont = ttLib.TTFont('broken.ttf')\n\n# after — filter cmap entries to defined Unicode ranges before embedding\ncmap = font.getBestCmap()\nfor cp in list(cmap.keys()):\n    if cp > 0x2FFFF:  # drop problematic supplementary/private-use\n        del cmap[cp]\nfont.save('fixed.ttf')","handlingStrategy":"validation","validationCode":"// Server-side: check Unicode code points against OS/2 range limits\n// before embedding the font.\n// from fontTools import ttLib\n// font = ttLib.TTFont('font.ttf')\n// cmap = font.getBestCmap()\n// for cp in cmap:\n//     if cp > 0xE01EF and cp < 0xF0000:  # supplementary private use etc.\n//         print(f'Warning: code point U+{cp:04X} may exceed OS/2 range 123')\nfunction checkUnicodeRanges(font) {\n  const cmap = font.tables.cmap;\n  // Inspect code points; anything in very high planes may trigger this\n  const risky = cmap.codePoints.filter(cp => cp > 0x3FFFF);\n  return risky.length === 0;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await page.render(renderParams).promise;\n} catch (err) {\n  if (err.message?.includes('Unicode ranges Bits > 123')) {\n    console.warn('Font has code points beyond defined OS/2 Unicode ranges; font load failed.');\n  } else { throw err; }\n}","preventionTips":["Filter out private-use and unassigned Unicode code points from font cmaps before embedding.","Rebuild the OS/2 table with fonttools after cleaning the cmap.","Use ots-sanitize to validate OS/2 table integrity."],"tags":["font","os2","unicode","opentype","truetype","format-error"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}