{"record":{"id":"3c540964a55dc789","repo":"siyuan-note/siyuan","slug":"parse-font-failed-v","errorCode":null,"errorMessage":"parse font failed: %v","messagePattern":"parse font failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/custom_font.go","lineNumber":323,"sourceCode":"\t\treturn \".otf\", nil\n\tdefault:\n\t\treturn \"\", errors.New(\"only TTF and OTF font files are supported\")\n\t}\n}\n\nfunc customFontHash(reader io.Reader) (string, error) {\n\thash := sha256.New()\n\tif _, err := io.Copy(hash, reader); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(hash.Sum(nil)), nil\n}\n\nfunc parseCustomFontFile(fontFile *os.File) (ret *Font, err error) {\n\tdefer func() {\n\t\tif recovered := recover(); recovered != nil {\n\t\t\tret = nil\n\t\t\terr = fmt.Errorf(\"parse font failed: %v\", recovered)\n\t\t}\n\t}()\n\n\tparsed, err := sfnt.Parse(fontFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse font failed: %w\", err)\n\t}\n\tret, err = parseFontInfo(parsed)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse font metadata failed: %w\", err)\n\t}\n\treturn ret, nil\n}\n\nfunc validCustomFontID(id string) bool {\n\tif len(id) != sha256.Size*2 || strings.ToLower(id) != id {\n\t\treturn false\n\t}","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/custom_font.go#L305-L341","documentation":"Returned by parseCustomFontFile from its deferred recover() when the sfnt parser (golang.org/x/fonts/sfnt via ConradIrwin/font) panics while reading the font. The panic value is formatted with %v and wrapped as 'parse font failed: <value>'. This is a safety net around a third-party library that panics on malformed input.","triggerScenarios":"InstallCustomFont or loadCustomFontsLocked passes a font file that passes the magic-byte check but is structurally malformed enough to make the sfnt parser panic during table parsing.","commonSituations":"A deliberately fuzzed or corrupted font; a font where required tables (head, name, OS/2) are missing or truncated; a font that survived the 4-byte header check but is otherwise garbage.","solutions":["Re-download or replace the font file — it is corrupt and cannot be installed.","Validate the font with an external tool (fonttools, otfproof, or FontForge) before uploading to identify the broken table.","If the panic is reproducible from a legitimate file, report it upstream to the sfnt parser with the triggering file."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, _, err := util.InstallCustomFont(tempPath); err != nil {\n    if strings.Contains(err.Error(), \"parse font failed\") {\n        // corrupt font: ask the user for a fresh copy\n    }\n}","preventionTips":["Validate fonts with fonttools/ttx before offering them for install.","Treat 'parse font failed: <panic>' as a corrupt-input signal, not a bug to retry."],"tags":["fonts","parsing","panic","sfnt"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}