{"record":{"id":"67eaa96adcc9a68b","repo":"siyuan-note/siyuan","slug":"only-ttf-and-otf-font-files-are-supported","errorCode":null,"errorMessage":"only TTF and OTF font files are supported","messagePattern":"only TTF and OTF font files are supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/custom_font.go","lineNumber":307,"sourceCode":"\t\tif _, active := customFontTemps[tempPath]; !active {\n\t\t\t_ = os.Remove(tempPath)\n\t\t}\n\t}\n}\n\nfunc detectCustomFontExtension(reader io.Reader) (string, error) {\n\theader := make([]byte, 4)\n\tif _, err := io.ReadFull(reader, header); err != nil {\n\t\treturn \"\", errors.New(\"font file is invalid\")\n\t}\n\n\tswitch string(header) {\n\tcase \"\\x00\\x01\\x00\\x00\", \"true\":\n\t\treturn \".ttf\", nil\n\tcase \"OTTO\":\n\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}()","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/custom_font.go#L289-L325","documentation":"Returned by detectCustomFontExtension when the 4-byte magic header does not match any supported signature. Accepted magics are \\x00\\x01\\x00\\x00 and 'true' (TTF) and 'OTTO' (OTF). WOFF, WOFF2, EOT, and other container formats are rejected even though their payload may contain TTF/OTF data.","triggerScenarios":"Calling InstallCustomFont with a font whose first 4 bytes are not the TTF/OTF signature — typically WOFF (magic 'wOFF'), WOFF2 ('wOF2'), EOT, or a non-font file that happens to be at least 4 bytes.","commonSituations":"A user downloaded a WOFF/WOFF2 web font (common from Google Fonts) and tried to install it directly; a variable font packaged in a container format; a renamed non-font file with a .ttf extension.","solutions":["Convert the font to a plain TTF or OTF before uploading (e.g. fonttools pyftfontforge, or download the TTF/OTF variant directly).","Re-download from the source choosing the .ttf or .otf file rather than .woff/.woff2.","Verify the file is actually a font and not a renamed archive or image."],"exampleFix":"// before\nutil.InstallCustomFont(tempPath) // tempPath holds a .woff\n\n// after\n// convert first:  pyftsubset font.woff --output-file=font.ttf\n// or download the TTF variant, then:\nutil.InstallCustomFont(tempPathTTF)","handlingStrategy":"validation","validationCode":"func supportedFontMagic(header []byte) bool {\n    switch string(header[:4]) {\n    case \"\\x00\\x01\\x00\\x00\", \"true\", \"OTTO\": return true\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Convert WOFF/WOFF2 to TTF/OTF before uploading.","Tell users which formats are accepted in the upload UI."],"tags":["fonts","validation","parsing","file-format"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}