siyuan-note/siyuan · error

parse font failed

Error message

parse font failed: %w

What it means

parseCustomFontFile calls sfnt.Parse to parse the font binary. This error is the normal (non-panic) parse-failure path: sfnt.Parse returned an error because the file, despite passing the 4-byte magic sniff, is not a structurally valid TrueType/OpenType font, and the cause is wrapped with %w so errors.Is/As work.

Solutions

  1. Re-download or re-export the font; verify integrity against a known checksum
  2. Validate locally with fonttools (ttx font.ttf) which reports the broken table
  3. Ensure any transfer used binary mode and completed fully
  4. Remove the broken file from the custom fonts directory if it cannot be repaired
Defensive patterns

Strategy: try-catch

Try / catch

font, _, err := util.InstallCustomFont(tempPath)
var cause error
if err != nil && errors.As(err, &cause) {
    log.Printf("font parse failed: %v", cause) // inspect wrapped sfnt error
}

Prevention

When it happens

Trigger: Calling InstallCustomFont or loadCustomFontsLocked on a file with a valid TTF/OTF magic header but broken/missing required tables (e.g. truncated 'glyf'/'cff' data, bad offsets).

Common situations: Fonts truncated during download after the first 4 bytes; fonts corrupted by binary-unsafe transfer (e.g. text-mode FTP); hand-edited or subsetted files produced by buggy tooling.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at kernel/util/custom_font.go:334

func customFontHash(reader io.Reader) (string, error) {
	hash := sha256.New()
	if _, err := io.Copy(hash, reader); err != nil {
		return "", err
	}
	return hex.EncodeToString(hash.Sum(nil)), nil
}

func parseCustomFontFile(fontFile *os.File) (ret *Font, err error) {
	defer func() {
		if recovered := recover(); recovered != nil {
			ret = nil
			err = fmt.Errorf("parse font failed: %v", recovered)
		}
	}()

	parsed, err := sfnt.Parse(fontFile)
	if err != nil {
		return nil, fmt.Errorf("parse font failed: %w", err)
	}
	ret, err = parseFontInfo(parsed)
	if err != nil {
		return nil, fmt.Errorf("parse font metadata failed: %w", err)
	}
	return ret, nil
}

func validCustomFontID(id string) bool {
	if len(id) != sha256.Size*2 || strings.ToLower(id) != id {
		return false
	}
	decoded, err := hex.DecodeString(id)
	return err == nil && len(decoded) == sha256.Size
}

func newCustomFont(id, fontPath string, font *Font) *CustomFont {
	weight := font.Weight

View on GitHub (pinned to 9f775e8a12)