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

  1. Re-obtain the font file from a trusted source and verify its size/checksum.
  2. Validate the font loads with a reference parser (e.g. gofont sfnt or fonttools) before feeding it to the library.
  3. 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).
  4. 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

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


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/30b1d52db2d3b438. Report an issue: GitHub.