subframe7536/maple-font · error · ValueError

No OS/2 table found.

Error message

No OS/2 table found.

What it means

adjust_line_height modifies both hhea and OS/2 line-gap/typo metrics; the OS/2 table holds the Windows typo ascender/descender values. This ValueError is raised when the 'OS/2' table is absent from the font object. Without OS/2, the function cannot keep Windows-platform line metrics in sync, so it refuses to run.

Source

Thrown at source/py/utils.py:417

    axisValRec.Flags = 0
    axisValRec.Format = 1
    axisValRec.ValueNameID = id
    axisValRec.Value = 1.0
    stat_table.AxisValueArray.AxisValue.append(axisValRec)
    stat_table.AxisValueCount += 1


def adjust_line_height(
    font: TTFont, factor: float, metric: tuple[float, float]
) -> None:
    """
    Adjust the line height of the font by modifying the hhea and OS/2 table.
    """

    if "hhea" not in font:
        raise ValueError("No hhea table found.")
    if "OS/2" not in font:
        raise ValueError("No OS/2 table found.")

    head = font["head"]
    hhea = font["hhea"]
    os2 = font["OS/2"]

    asc, desc = metric
    # Maintain original ascender/descender ratio
    ascender_ratio = asc / (asc - desc)  # type: ignore
    # Calculate target total height
    target_total_height = int(round(factor * (asc - desc)))

    # Calculate new metrics
    new_ascender = int(round(target_total_height * ascender_ratio))
    new_descender = new_ascender - target_total_height

    print(f"Change vertical metric to [{new_ascender}, {new_descender}]")

    # Apply changes to hhea table

View on GitHub (pinned to c08fda97fe)

Solutions

  1. Rebuild/repair the source font so it includes an OS/2 table (fonttools or a font editor can add one).
  2. Confirm "OS/2" in font after loading with fontTools TTFont before calling adjust_line_height.
  3. Check the subsetting/conversion step didn't drop OS/2 (use --no-subset-tables or equivalent options).
  4. Point the build at the correct upstream TTF source file.

Example fix

// before
# adjust_line_height(font, metric)  # raises: No OS/2 table found.
// after
# if "OS/2" not in font or "hhea" not in font:
#     raise RuntimeError("font lacks required hhea/OS/2 tables")
# adjust_line_height(font, metric)
Defensive patterns

Strategy: type-guard

Validate before calling

from fontTools.ttLib import TTFont

def require_tables(path, tables=("hhea", "OS/2")):
    font = TTFont(path)
    missing = [t for t in tables if t not in font]
    if missing:
        raise ValueError(f"{path} missing tables: {missing}")
    return font

Type guard

def has_os2(font) -> bool:
    return "OS/2" in font  # fontTools TTFont supports __contains__

Try / catch

try:
    adjust_line_height(font, metric)
except ValueError as e:
    if str(e) == "No OS/2 table found.":
        raise RuntimeError("Font lacks OS/2 table; use a font exported with OS/2 metrics") from e
    raise

Prevention

When it happens

Trigger: Calling adjust_line_height (via build_nf, build_cn, or build_variable_fonts) on a font where "OS/2" not in font — typically a legacy font lacking OS/2, a stripped/subsetted font, or a corrupted/incorrectly converted font object.

Common situations: Using an old Type 1 or legacy-converted font lacking OS/2; a subsetting tool dropped the OS/2 table; passing a font object whose tables weren't lazily loaded properly; building from a source font produced by an unusual toolchain.

Related errors


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