siyuan-note/siyuan · warning

font family is empty

Error message

font family is empty

What it means

parseFontInfo extracts font metadata (family, subfamily, weight) from a parsed font file. The family name is mandatory for registering a custom font; a missing family or one starting with a period (hidden/internal fonts like '.AppleSystemUIFont') is rejected and the font file is skipped.

Solutions

  1. Remove the offending font file from the custom fonts directory and re-import a valid TTF/OTF/WOFF
  2. Check the font with fonttools/FontForge to confirm it has a family name (name ID 1/16)
  3. Skip dot-prefixed fonts explicitly when scanning system font folders
  4. Re-download the font from a trusted source if the file is truncated

Example fix

// before: scanning all files in the fonts dir
for _, f := range files { parseFont(f) }
// after: skip hidden/internal fonts
if strings.HasPrefix(f.Name(), ".") { continue }
Defensive patterns

Strategy: validation

Validate before calling

if family == "" || strings.HasPrefix(family, ".") {
    return fmt.Errorf("skipping font %q: no usable family name", path)
}

Prevention

When it happens

Trigger: parseFont, parseCustomFontFile, or TestParseBundledFontLocalizedName encounter a font whose name table yields an empty family, or whose family begins with '.' (system-internal hidden fonts).

Common situations: User imports a broken/corrupt custom font; scanning system font directories containing internal dot-prefixed Apple/Windows fonts; a truncated TTF/OTF missing its name-table records.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/0710195c30d7cd67. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/font.go:313

	localizedFamily := selectLocalizedFontName(entries, sfnt.NamePreferredFamily, sfnt.NameFontFamily)
	localizedSubfamily := selectLocalizedFontName(entries, sfnt.NamePreferredSubfamily, sfnt.NameFontSubfamily)
	if "" == localizedFamily {
		localizedFamily = family
	}
	if "" == localizedSubfamily {
		localizedSubfamily = subfamily
	}

	weight := 400
	os2, err := font.OS2Table()
	if nil == err {
		weight = int(os2.USWeightClass)
	}

	weight = inferFontWeight(weight, subfamily)

	if family == "" || strings.HasPrefix(family, ".") {
		return nil, errors.New("font family is empty")
	}

	displayName := localizedFamily
	if subfamily != "" && !strings.EqualFold(subfamily, "Regular") {
		displayName = localizedFamily + " " + localizedSubfamily
	}
	aliases := collectFontAliases(entries,
		sfnt.NamePreferredFamily, sfnt.NameFontFamily, sfnt.NameWWSFamily,
		sfnt.NamePreferredSubfamily, sfnt.NameFontSubfamily, sfnt.NameWWSSubfamily,
		sfnt.NameFull, sfnt.NameCompatibleFull, sfnt.NamePostscript)

	return &Font{
		nonNormalStyle: isNonNormalFontStyle(subfamily),
		Family:         family,
		Weight:         weight,
		DisplayName:    displayName,
		Aliases:        aliases,
		Spacing:        detectFontSpacing(font),

View on GitHub (pinned to 9f775e8a12)