{"record":{"id":"2c943b71acc859d0","repo":"siyuan-note/siyuan","slug":"invalid-custom-font-id","errorCode":null,"errorMessage":"invalid custom font ID","messagePattern":"invalid custom font ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/custom_font.go","lineNumber":172,"sourceCode":"\t} else if !os.IsNotExist(statErr) {\n\t\treturn nil, false, statErr\n\t}\n\n\tif err = os.Rename(tempPath, targetPath); err != nil {\n\t\treturn nil, false, err\n\t}\n\tif err = os.Chmod(targetPath, 0644); err != nil {\n\t\t_ = os.Remove(targetPath)\n\t\treturn nil, false, err\n\t}\n\n\tcustomFontsLoaded = false\n\treturn newCustomFont(id, targetPath, font), true, nil\n}\n\nfunc RemoveCustomFont(id string) (*CustomFont, error) {\n\tif !validCustomFontID(id) {\n\t\treturn nil, errors.New(\"invalid custom font ID\")\n\t}\n\n\tcustomFontsLock.Lock()\n\tdefer customFontsLock.Unlock()\n\n\tloadCustomFontsLocked()\n\tfor _, font := range customFonts {\n\t\tif font.ID != id {\n\t\t\tcontinue\n\t\t}\n\t\tif err := os.Remove(font.path); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcustomFontsLoaded = false\n\t\treturn cloneCustomFont(font), nil\n\t}\n\treturn nil, os.ErrNotExist\n}","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/custom_font.go#L154-L190","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n_, err := util.RemoveCustomFont(font.Family)\n// after\nid := strings.TrimPrefix(font.ID, \"SiYuanCustomFont-\")\nid = strings.ToLower(id)\n_, err := util.RemoveCustomFont(id)","handlingStrategy":"validation","validationCode":"func isValidFontID(id string) bool {\n    if len(id) != 64 { return false }\n    _, err := hex.DecodeString(id)\n    return err == nil && strings.ToLower(id) == id\n}","typeGuard":null,"tryCatchPattern":"_, err := util.RemoveCustomFont(id)\nif err != nil && err.Error() == \"invalid custom font ID\" {\n    // look up the correct ID via util.LoadCustomFonts()\n}","preventionTips":["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"],"tags":["validation","identifier","custom-font"],"backgroundTag":"invalid-identifier-format","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}