subframe7536/maple-font · error · ValueError

Font does not have an OS/2 table.

Error message

Font does not have an OS/2 table.

What it means

auto_xheight_capheight() needs the OS/2 table to write sxHeight and sCapHeight. If the TTFont has no 'OS/2' table it raises this ValueError immediately. Fonts produced by very old or minimal toolchains, or some icon/bitmap-derived fonts, may omit OS/2.

Source

Thrown at source/py/task/merge_font/utils.py:179

def _get_glyph_bounds(font, glyph_name):
    """Get (yMin, yMax) of a glyph by name from 'glyf' table."""
    glyph_order = font.getGlyphOrder()
    if glyph_name not in glyph_order:
        raise ValueError(f"Glyph '{glyph_name}' not found in font.")
    glyf = font["glyf"]
    glyph = glyf[glyph_name]
    if glyph.numberOfContours == 0:
        # Empty glyph
        return (0, 0)
    y_min = glyph.yMin
    y_max = glyph.yMax
    return (y_min, y_max)


def auto_xheight_capheight(font: TTFont):
    if "OS/2" not in font:
        raise ValueError("Font does not have an OS/2 table.")
    if "glyf" not in font:
        raise ValueError(
            "This script only supports TrueType (glyf) fonts. CFF support not implemented."
        )

    try:
        # Get bounds
        z_ymin, z_ymax = _get_glyph_bounds(font, "z")
        Z_ymin, Z_ymax = _get_glyph_bounds(font, "Z")

        x_height = round(z_ymax)  # xHeight = top of lowercase 'z'
        cap_height = round(Z_ymax)  # capHeight = top of uppercase 'Z'

        # Update OS/2 table
        os2 = font["OS/2"]
        os2.sxHeight = x_height  # type: ignore
        os2.sCapHeight = cap_height  # type: ignore
    except Exception as e:

View on GitHub (pinned to c08fda97fe)

Solutions

  1. Add an OS/2 table with fontTools (e.g. copy from a base font or use fontTools.ttLib.newTable('OS/2') and set required fields).
  2. Regenerate the font from its source with a modern compiler (fontmake/glyphs) so OS/2 is emitted.
  3. Skip the auto x-height step for such fonts and keep existing OS/2 metrics (or guard the call with `if 'OS/2' in font`).

Example fix

# before
auto_xheight_capheight(font)

# after
if "OS/2" in font:
    auto_xheight_capheight(font)
Defensive patterns

Strategy: type-guard

Validate before calling

if "OS/2" not in font:
    raise RuntimeError("input font lacks OS/2 table; regenerate or add table before polish()")

Type guard

def has_required_tables(font, tables=("OS/2", "glyf", "hhea")) -> bool:
    return all(t in font for t in tables)

Try / catch

try:
    auto_xheight_capheight(font)
except ValueError as e:
    if "OS/2" in str(e):
        font["OS/2"] = newTable("OS/2")  # or skip step
    else:
        raise

Prevention

When it happens

Trigger: Calling polish() with a line_height/metrics step that triggers auto_xheight_capheight on a font whose table directory lacks 'OS/2' (font['OS/2'] would KeyError, so the explicit check raises first).

Common situations: Legacy fonts predating OS/2; fonts converted from formats that don't carry OS/2; minimal test/icon fonts; fonts heavily stripped by subsetting tools that dropped the table.

Related errors


AI-assisted analysis of subframe7536/maple-font@c08fda97fe (2026-08-28). Data as JSON: /api/errors/cd90ece590a8a024. Report an issue: GitHub.