mozilla/pdf.js · error · FormatError

unknown operator: 12 ${v}

Error message

unknown operator: 12 ${v}

What it means

Thrown during CFF (Compact Font Format) charstring interpretation when a two-byte escape operator (first byte 12) has a second byte 'v' that is not one of the recognized flex operators (34=hflex, 35=flex, 36=hflex1, 37=flex1). CFF charstrings use byte 12 as an escape prefix for extended operators; only a subset is implemented in the font renderer.

Source

Thrown at src/core/font_renderer.js:539

              yb = ya + stack.shift();
              x = xb + stack.shift();
              y = yb + stack.shift();
              bezierCurveTo(xa, ya, xb, yb, x, y);
              xa = x + stack.shift();
              ya = y + stack.shift();
              xb = xa + stack.shift();
              yb = ya + stack.shift();
              x = xb;
              y = yb;
              if (Math.abs(x - x0) > Math.abs(y - y0)) {
                x += stack.shift();
              } else {
                y += stack.shift();
              }
              bezierCurveTo(xa, ya, xb, yb, x, y);
              break;
            default:
              throw new FormatError(`unknown operator: 12 ${v}`);
          }
          break;
        case 14: // endchar
          if (stack.length >= 4) {
            const achar = stack.pop();
            const bchar = stack.pop();
            y = stack.pop();
            x = stack.pop();
            cmds.save();
            cmds.translate(x, y);
            let cmap = lookupCmap(
              font.cmap,
              String.fromCharCode(font.glyphNameMap[StandardEncoding[achar]])
            );
            compileCharString(
              font.glyphs[cmap.glyphId],
              cmds,
              font,

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Rebuild or re-export the font with fonttools (pyftsubset or ttx) to normalize charstrings to standard Type 2 operators.
  2. Replace the embedded font in the PDF with a well-formed CFF font.
  3. Update pdf.js — some operators may be added in future releases.
  4. If you produce CFF fonts, avoid deprecated two-byte operators (12-0 through 12-12) that the renderer doesn't implement.

Example fix

# normalize CFF charstrings with fonttools
from fontTools import ttLib
font = ttLib.TTFont('broken.otf')
font.save('fixed.otf')  # round-trip normalizes charstring operators
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate CFF charstring operators with fonttools (Python, server-side)
// from fontTools.cff import CFFFontSet
// from fontTools.misc.psCharStrings import T2Charstring
// Check for unsupported 12-escaped operators by iterating charstrings.
function validateCffCharstrings(fontPath) {
  // Requires running fonttools in a subprocess or server-side Python
  // Returns list of glyphs with unsupported operators
}

Try / catch

// CompiledFont.getPath catches compileGlyph errors internally and caches them.
// The re-thrown Error surfaces during page rendering:
try {
  await page.render(renderParams).promise;
} catch (err) {
  if (err.message?.startsWith('unknown operator: 12')) {
    // Specific CFF glyph failed; page rendering continues for other glyphs
    console.warn('Unsupported CFF flex operator in a glyph; glyph skipped.');
  } else { throw err; }
}

Prevention

When it happens

Trigger: compileGlyphImpl() encounters byte 12 in a CFF Type 2 charstring, reads the next byte v, and v is not 34, 35, 36, or 37. Other valid two-byte CFF operators (e.g., 12-0 Copyright, 12-3 And, 12-9 vstem3) are not implemented in the rendering path.

Common situations: CFF/OpenType fonts with two-byte charstring operators beyond the flex family (e.g., 12-34 through 12-37). Corrupt charstring data where a byte is misread as operator 12. Non-standard fonts from niche type foundries using uncommon CFF operators. Note: the error is re-thrown from a cached Error in CompiledFont.getPath.

Related errors


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