{"record":{"id":"a7e5617e19adf05b","repo":"siyuan-note/siyuan","slug":"template-source-is-not-utf-8","errorCode":null,"errorMessage":"template source is not UTF-8","messagePattern":"template source is not UTF-8","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_manage.go","lineNumber":163,"sourceCode":"\t\th.Write(content)\n\t}\n\treturn fmt.Sprintf(\"%x\", h.Sum(nil)), err\n}\n\nfunc readTemplateSource(root *os.Root, p string) (string, error) {\n\tinfo, err := root.Stat(p)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif !info.Mode().IsRegular() || info.Size() > maxTemplateSourceSize {\n\t\treturn \"\", errors.New(\"invalid template source file\")\n\t}\n\tcontent, err := root.ReadFile(p)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif !utf8.Valid(content) {\n\t\treturn \"\", errors.New(\"template source is not UTF-8\")\n\t}\n\treturn string(content), nil\n}\n\n// 同目录临时文件写入完成后替换，写入失败时保留原模板。\nfunc writeTemplateSource(root *os.Root, p, content string, create bool) error {\n\tif !utf8.ValidString(content) {\n\t\treturn errors.New(\"invalid template source\")\n\t}\n\tif create {\n\t\tfile, err := root.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = file.WriteString(content)\n\t\tif err == nil {\n\t\t\terr = file.Sync()\n\t\t}","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_manage.go#L145-L181","documentation":"readTemplateSource validates that the bytes it read from the template file are valid UTF-8 before converting them to a Go string, because template content is processed as UTF-8 text throughout SiYuan. If the file contains invalid byte sequences (binary data, GBK/Latin-1 encoded text, a truncated multi-byte character), the read is rejected with this error rather than returning mojibake.","triggerScenarios":"ManageTemplateFiles with action=\"read\" on a .md template whose on-disk bytes are not valid UTF-8 — e.g. the file was saved by an editor with a legacy encoding (GBK, Shift-JIS, Latin-1), or contains binary/embedded content from a bad copy.","commonSituations":"A Windows editor saved the template as ANSI/GBK; a file was uploaded or synced with encoding conversion; a partially transferred file was truncated mid multi-byte character.","solutions":["Re-save the template file as UTF-8 (without BOM is fine) in your editor and retry the read","Convert the file with an encoding tool, e.g. iconv -f GBK -t UTF-8 template.md -o template.md","If the content is binary, it does not belong in data/templates; move it elsewhere"],"exampleFix":"// before: template.md encoded in GBK\n$ iconv -f GBK -t UTF-8 template.md > template.utf8.md\n$ mv template.utf8.md template.md\n// after: file is valid UTF-8 and reads successfully","handlingStrategy":"validation","validationCode":"const buf = fs.readFileSync(absPath);\nif (!buf.equals(Buffer.from(buf.toString('utf8'), 'utf8'))) {\n  throw new Error('file is not valid UTF-8; convert before using as a template');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await manageTemplateFiles({ action: 'read', path: p });\n} catch (e) {\n  if (String(e.message).includes('not UTF-8')) {\n    // prompt the user to re-save as UTF-8, or convert with iconv and retry once\n  }\n}","preventionTips":["Always save templates with UTF-8 encoding in your editor","Run `file -bi template.md` or iconv validation on files imported from other systems","Never copy binary data into .md templates"],"tags":["encoding","utf-8","template","validation"],"backgroundTag":"invalid-encoding","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}