siyuan-note/siyuan · error

template source is not UTF-8

Error message

template source is not UTF-8

What it means

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.

Source

Thrown at kernel/model/template_manage.go:163

		h.Write(content)
	}
	return fmt.Sprintf("%x", h.Sum(nil)), err
}

func readTemplateSource(root *os.Root, p string) (string, error) {
	info, err := root.Stat(p)
	if err != nil {
		return "", err
	}
	if !info.Mode().IsRegular() || info.Size() > maxTemplateSourceSize {
		return "", errors.New("invalid template source file")
	}
	content, err := root.ReadFile(p)
	if err != nil {
		return "", err
	}
	if !utf8.Valid(content) {
		return "", errors.New("template source is not UTF-8")
	}
	return string(content), nil
}

// 同目录临时文件写入完成后替换,写入失败时保留原模板。
func writeTemplateSource(root *os.Root, p, content string, create bool) error {
	if !utf8.ValidString(content) {
		return errors.New("invalid template source")
	}
	if create {
		file, err := root.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
		if err != nil {
			return err
		}
		_, err = file.WriteString(content)
		if err == nil {
			err = file.Sync()
		}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Re-save the template file as UTF-8 (without BOM is fine) in your editor and retry the read
  2. Convert the file with an encoding tool, e.g. iconv -f GBK -t UTF-8 template.md -o template.md
  3. If the content is binary, it does not belong in data/templates; move it elsewhere

Example fix

// before: template.md encoded in GBK
$ iconv -f GBK -t UTF-8 template.md > template.utf8.md
$ mv template.utf8.md template.md
// after: file is valid UTF-8 and reads successfully
Defensive patterns

Strategy: validation

Validate before calling

const buf = fs.readFileSync(absPath);
if (!buf.equals(Buffer.from(buf.toString('utf8'), 'utf8'))) {
  throw new Error('file is not valid UTF-8; convert before using as a template');
}

Try / catch

try {
  await manageTemplateFiles({ action: 'read', path: p });
} catch (e) {
  if (String(e.message).includes('not UTF-8')) {
    // prompt the user to re-save as UTF-8, or convert with iconv and retry once
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/a7e5617e19adf05b. Report an issue: GitHub.