d2lang/d2 · error
invalid kern table: too short
Error message
invalid kern table: too short
What it means
parseLegacyKern reads the legacy 'kern' table of an sfnt (TrueType/OpenType) font to extract kerning pairs. A valid kern table header plus subtable header needs at least 18 bytes; a shorter table cannot be parsed safely, so the font is rejected.
Source
Thrown at lib/textmeasure/fontface.go:159
}
func roundScale(scale, units, unitsPerEm fixed.Int26_6) fixed.Int26_6 {
x := int64(scale) * int64(units)
if x >= 0 {
x += int64(unitsPerEm) / 2
} else {
x -= int64(unitsPerEm) / 2
}
return fixed.Int26_6(x / int64(unitsPerEm))
}
func parseLegacyKern(src []byte) ([]kernPair, error) {
table, err := sfntTable(src, "kern")
if err != nil || table == nil {
return nil, err
}
if len(table) < 18 {
return nil, fmt.Errorf("invalid kern table: too short")
}
if binary.BigEndian.Uint16(table[0:2]) != 0 {
return nil, fmt.Errorf("unsupported kern table version")
}
if binary.BigEndian.Uint16(table[2:4]) == 0 {
return nil, fmt.Errorf("invalid kern table: no subtables")
}
length := int(binary.BigEndian.Uint16(table[6:8]))
coverage := binary.BigEndian.Uint16(table[8:10])
if coverage != 0x0001 {
return nil, fmt.Errorf("unsupported kern table coverage 0x%04x", coverage)
}
n := int(binary.BigEndian.Uint16(table[10:12]))
if length < 14 || 6*n != length-14 || 4+length > len(table) {
return nil, fmt.Errorf("invalid kern table length")
}
View on GitHub (pinned to 0d69dca6f5)
Solutions
- Re-obtain the font file from a trusted source and verify its size/checksum.
- Validate the font loads with a reference parser (e.g. gofont sfnt or fonttools) before feeding it to the library.
- If the font is intentionally subsetted, re-subset with kern data included or stripped entirely (a missing kern table is fine; a truncated one is not).
- Remove the corrupt 'kern' table with fonttools (ttLib) so sfntTable returns nil and kerning parsing is skipped.
Example fix
# before: corrupt font loads with truncated kern table
# after: strip the broken table so the library skips kerning
fonttools ttLib.woff2 compress -o fixed.woff2 broken.ttf
# or in python:
# from fontTools.ttLib import TTFont
# f = TTFont('broken.ttf'); del f['kern']; f.save('fixed.ttf') Defensive patterns
Strategy: validation
Validate before calling
func kernTablePlausible(font []byte) bool {
t, err := sfntTable(font, "kern")
return err == nil && (t == nil || len(t) >= 18)
} Try / catch
pairs, err := parseLegacyKern(fontData)
if err != nil {
log.Printf("kerning disabled: %v", err)
pairs = nil // proceed without kerning
} Prevention
- Verify font file integrity (size/checksum) after download and before embedding
- Never commit truncated fonts; use go:embed on verified assets
- Test all bundled fonts at startup so corruption is caught early
- Strip rather than truncate unused tables when subsetting fonts
When it happens
Trigger: Calling fontface/parseFont (via NewFontFace initialization) on a font whose 'kern' table exists but is truncated to fewer than 18 bytes — typically a corrupted or partially downloaded font file.
Common situations: Truncated font files from interrupted downloads; fonts embedded in PDFs and extracted incompletely; hand-trimmed/subsetted fonts where the kern table was cut short.
Related errors
- unsupported kern table version
- invalid kern table: no subtables
- unsupported kern table coverage 0x%04x
- invalid kern table length
- invalid sfnt: too short
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/30b1d52db2d3b438.
Report an issue: GitHub.