d2lang/d2 · error

invalid font collection

Error message

invalid font collection

What it means

For TrueType collections (ttcf), bytes 8–12 hold the offset of the first font in the collection; it must be non-zero and the file must be at least 16 bytes. A zero offset or too-short collection header is rejected.

Source

Thrown at lib/textmeasure/fontface.go:197

	for i := range pairs {
		offset := 18 + 6*i
		pairs[i] = kernPair{
			key:   binary.BigEndian.Uint32(table[offset : offset+4]),
			value: int16(binary.BigEndian.Uint16(table[offset+4 : offset+6])),
		}
	}
	return pairs, nil
}

func sfntTable(src []byte, tag string) ([]byte, error) {
	if len(src) < 12 {
		return nil, fmt.Errorf("invalid sfnt: too short")
	}

	base := 0
	if string(src[:4]) == "ttcf" {
		if len(src) < 16 || binary.BigEndian.Uint32(src[8:12]) == 0 {
			return nil, fmt.Errorf("invalid font collection")
		}
		base = int(binary.BigEndian.Uint32(src[12:16]))
		if base < 0 || base+12 > len(src) {
			return nil, fmt.Errorf("invalid font collection offset")
		}
	}

	n := int(binary.BigEndian.Uint16(src[base+4 : base+6]))
	records := base + 12
	if n > (len(src)-records)/16 {
		return nil, fmt.Errorf("invalid sfnt table directory")
	}
	for i := 0; i < n; i++ {
		record := src[records+16*i : records+16*(i+1)]
		if string(record[:4]) != tag {
			continue
		}
		offset := int(binary.BigEndian.Uint32(record[8:12]))

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Re-acquire the .ttc file from a trusted source.
  2. Split the collection into single .ttf fonts (e.g. with fonttools: fonttools ttLib.ttCollection) and use individual fonts.
  3. Validate the ttcf header (magic, version, non-zero offsets) before passing the data to the library.
Defensive patterns

Strategy: validation

Validate before calling

func validTTC(data []byte) bool {
    if len(data) < 16 || string(data[:4]) != "ttcf" { return len(data) >= 12 }
    return binary.BigEndian.Uint32(data[8:12]) != 0
}

Try / catch

if err := loadAndParseFont(path); err != nil {
    log.Printf("font collection unusable (%v); falling back to single font", err)
    return loadSingleFont(fallbackPath)
}

Prevention

When it happens

Trigger: parseFont is given a .ttc font collection whose header declares version 'ttcf' but has a zero first-font offset or a truncated (<16 byte) header.

Common situations: Corrupted or hand-merged .ttc files; fonts harvested from system font caches in partial form.

Related errors


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