mozilla/pdf.js · error · FormatError

unsupported cmap: ${format}

Error message

unsupported cmap: ${format}

What it means

Thrown by parseCmap() in font_renderer.js when the font's cmap (character-to-glyph mapping) subtable has a format other than 4 (segment mapping) or 12 (segmented coverage). Only formats 4 and 12 are implemented in the font-rendering path; other formats (0, 2, 6, 13, 14, etc.) are rejected.

Source

Thrown at src/core/font_renderer.js:97

      }
    }
    return ranges;
  } else if (format === 12) {
    const groups = view.getUint32(start + offset + 12);
    p = start + offset + 16;
    ranges = [];
    for (i = 0; i < groups; i++) {
      start = view.getUint32(p);
      ranges.push({
        start,
        end: view.getUint32(p + 4),
        idDelta: view.getUint32(p + 8) - start,
      });
      p += 12;
    }
    return ranges;
  }
  throw new FormatError(`unsupported cmap: ${format}`);
}

function parseCff(data, start, end, seacAnalysisEnabled) {
  const properties = {};
  const parser = new CFFParser(
    new Stream(data, start, end - start),
    properties,
    seacAnalysisEnabled
  );
  const cff = parser.parse();
  return {
    glyphs: cff.charStrings.objects,
    subrs: cff.topDict.privateDict?.subrsIndex?.objects,
    gsubrs: cff.globalSubrIndex?.objects,
    isCFFCIDFont: cff.isCIDFont,
    fdSelect: cff.fdSelect,
    fdArray: cff.fdArray,
  };

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Use a font tool (fonttools/pyftsubset, FontForge) to convert the cmap to format 4 or 12 before embedding.
  2. Replace the problematic embedded font in the PDF with a standard font that has a format-4 or format-12 cmap.
  3. Update to the latest pdf.js version — newer versions may add support for additional cmap formats.
  4. If the font is system-provided, install a version that includes a format-4 cmap subtable.

Example fix

# before — subsetting with fonttools leaves format 0 cmap
pyftsubset font.ttf --unicodes=U+0041-005A

# after — force cmap format 4 output
pyftsubset font.ttf --unicodes=U+0041-U+005A --layout-features='*' --no-hinting
ttx -o fixed.ttf font.ttx  # ensure format 4 subtable is present
Defensive patterns

Strategy: validation

Validate before calling

// Server-side: check font cmap format before embedding
const opentype = require('opentype.js');
function hasSupportedCmap(fontPath) {
  const font = opentype.loadSync(fontPath);
  const cmap = font.tables.cmap;
  const formats = cmap.encodingRecords.map(r => {
    // format is read from the subtable; opentype.js resolves this
    return r.subtable ? r.subtable.format : null;
  });
  return formats.some(f => f === 4 || f === 12);
}

Try / catch

// Font rendering errors are caught internally by CompiledFont.getPath
// (font_renderer.js:823 caches the Error and re-throws on subsequent calls).
// At the display API level:
try {
  await page.render(renderParams).promise;
} catch (err) {
  if (err.message?.includes('unsupported cmap')) {
    console.warn('Font cmap format not supported for rendering; glyphs may be missing.');
  } else { throw err; }
}

Prevention

When it happens

Trigger: Calling parseCmap(data, start, end) where view.getUint16(start + offset) yields a format value that is neither 4 nor 12. This is invoked during font compilation (CompiledFont.setupPath) when building glyph path data for rendering.

Common situations: Fonts with legacy cmap formats (format 0 byte encoding, format 2 high-byte mapping for CJK, format 6 trimmed table, format 13 many-to-one, or format 14 variation selectors). Non-standard or minimally-built embedded fonts in PDFs. Fonts designed for specialized encodings that only ship format 6.

Related errors


AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13). Data as JSON: /api/errors/53184b2161f68055. Report an issue: GitHub.