{"record":{"id":"39559a57af9bc47f","repo":"subframe7536/maple-font","slug":"no-os-2-table-found","errorCode":null,"errorMessage":"No OS/2 table found.","messagePattern":"No OS/2 table found\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"source/py/task/merge_font/utils.py","lineNumber":259,"sourceCode":"    font: TTFont,\n    factor: float = 1.0,\n    metric: tuple[float, float] | None = None,\n    safe_metric: tuple[float, float] | None = None,\n) -> None:\n    \"\"\"\n    Adjust the line height of the font by modifying the hhea and OS/2 table.\n\n    Args:\n        font: The font to modify\n        factor: Scale factor to apply to metrics\n        metric: Tuple of (ascender, descender) for custom metrics\n        safe_metric: Tuple of (safe_ascender, safe_descender) for safe metrics\n    \"\"\"\n\n    if \"hhea\" not in font:\n        raise ValueError(\"No hhea table found.\")\n    if \"OS/2\" not in font:\n        raise ValueError(\"No OS/2 table found.\")\n\n    hhea = font[\"hhea\"]\n    os2 = font[\"OS/2\"]\n\n    if metric:\n        asc, desc = metric\n        safe_asc, safe_desc = safe_metric if safe_metric else (None, None)\n\n        # Maintain original ascender/descender ratio\n        ascender_ratio = asc / (asc - desc)  # type: ignore\n        # Calculate target total height\n        target_total_height = int(round(factor * (asc - desc)))\n\n        # Calculate new metrics\n        new_ascender = int(round(target_total_height * ascender_ratio))\n        new_descender = new_ascender - target_total_height\n\n        print(f\"Change vertical metric to [{new_ascender}, {new_descender}]\")","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/subframe7536/maple-font/blob/c08fda97fef73d68c1755219852150770f6e6578/source/py/task/merge_font/utils.py#L241-L277","documentation":"Companion check in change_line_height(): besides hhea, the 'OS/2' table (usWinAscent/usWinDescent and typo metrics) is required to keep line metrics consistent across platforms. If 'OS/2' is missing the function raises this ValueError.","triggerScenarios":"Calling change_line_height (via polish() with line_height config) on a font that has hhea but no OS/2 table.","commonSituations":"Legacy or stripped fonts missing OS/2; fonts from toolchains that omit OS/2 by default; pipeline earlier stages (like auto_xheight_capheight failing) hinting the same font lacks OS/2.","solutions":["Add an OS/2 table (fontTools newTable('OS/2'), set version, typo/win metrics) before adjusting line height.","Regenerate the font from a complete source so both hhea and OS/2 exist.","Guard the call to change_line_height with a table-presence check."],"exampleFix":"# before\npolish(font)  # line_height set, font lacks OS/2\n\n# after\nif \"OS/2\" in font and \"hhea\" in font:\n    polish(font)","handlingStrategy":"type-guard","validationCode":"assert \"OS/2\" in font, \"font must contain OS/2 table for line-height adjustment\"","typeGuard":"def can_change_line_height(font) -> bool:\n    return \"hhea\" in font and \"OS/2\" in font","tryCatchPattern":"try:\n    change_line_height(font, metric=(asc, desc))\nexcept ValueError as e:\n    if \"OS/2\" in str(e):\n        print(\"Skipping line-height: font has no OS/2 table\")\n    else:\n        raise","preventionTips":["Check for both hhea and OS/2 together — change_line_height needs both.","Add/repair OS/2 tables at font intake time, not at metric-edit time.","Regenerate stripped fonts from complete sources."],"tags":["python","fonts","fonttools","line-height"],"backgroundTag":"missing-font-table","analyzedSha":"c08fda97fef73d68c1755219852150770f6e6578","analyzedAt":"2026-08-28T22:07:29.503Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}