siyuan-note/siyuan · error
invalid custom font ID
Error message
invalid custom font ID
What it means
RemoveCustomFont requires the font ID to be a valid custom font identifier: exactly 64 lowercase hex characters (a lowercase SHA-256 hex digest). This error is thrown before any filesystem or registry work when the supplied ID fails that format check, since IDs are always derived by hashing the font file.
Solutions
- Use the exact ID string returned by LoadCustomFonts/InstallCustomFont (lowercase hex)
- Strip the "SiYuanCustomFont-" prefix if a family name was passed by mistake
- strings.ToLower the ID and verify len==64 and hex-decodable before calling
- List fonts with LoadCustomFonts and match by DisplayName to recover the correct ID
Example fix
// before _, err := util.RemoveCustomFont(font.Family) // after id := strings.TrimPrefix(font.ID, "SiYuanCustomFont-") id = strings.ToLower(id) _, err := util.RemoveCustomFont(id)
Defensive patterns
Strategy: validation
Validate before calling
func isValidFontID(id string) bool {
if len(id) != 64 { return false }
_, err := hex.DecodeString(id)
return err == nil && strings.ToLower(id) == id
} Try / catch
_, err := util.RemoveCustomFont(id)
if err != nil && err.Error() == "invalid custom font ID" {
// look up the correct ID via util.LoadCustomFonts()
} Prevention
- Only use IDs returned by LoadCustomFonts/InstallCustomFont
- Never pass family names or display names as IDs
- Store IDs verbatim; do not case-normalize before use
When it happens
Trigger: Calling RemoveCustomFont(id) with an ID that is not 64 chars, contains uppercase hex, or is not valid hex — e.g. passing a font family name, display name, a URL segment, or an ID captured with different casing.
Common situations: Frontend stored/serialized the ID with different casing; caller passed CustomFont.Family ("SiYuanCustomFont-<id>") instead of ID; hand-edited config referencing a made-up ID; older data using a different ID scheme.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- current document ID is invalid
- document versions do not belong to the same document
- ErrInvalidAttributeViewID
- ErrInvalidBoxID
- ErrInvalidID
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/2c943b71acc859d0.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/custom_font.go:172
} else if !os.IsNotExist(statErr) {
return nil, false, statErr
}
if err = os.Rename(tempPath, targetPath); err != nil {
return nil, false, err
}
if err = os.Chmod(targetPath, 0644); err != nil {
_ = os.Remove(targetPath)
return nil, false, err
}
customFontsLoaded = false
return newCustomFont(id, targetPath, font), true, nil
}
func RemoveCustomFont(id string) (*CustomFont, error) {
if !validCustomFontID(id) {
return nil, errors.New("invalid custom font ID")
}
customFontsLock.Lock()
defer customFontsLock.Unlock()
loadCustomFontsLocked()
for _, font := range customFonts {
if font.ID != id {
continue
}
if err := os.Remove(font.path); err != nil {
return nil, err
}
customFontsLoaded = false
return cloneCustomFont(font), nil
}
return nil, os.ErrNotExist
}View on GitHub (pinned to 9f775e8a12)