siyuan-note/siyuan · error

invalid template source

Error message

invalid template source

What it means

writeTemplateSource is the single write path for template content, used by both create and replace. It first verifies the incoming content string is valid UTF-8; since Go strings can technically hold invalid UTF-8 bytes (e.g. from raw byte slices or decoded JSON with escapes), this rejects content that could not be stored as a proper text template. The write is then performed atomically via a same-directory temp file and rename.

Source

Thrown at kernel/model/template_manage.go:171

		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()
		}
		closeErr := file.Close()
		if err != nil {
			root.Remove(p)
			return err
		}
		return closeErr
	}
	tmp := path.Join(path.Dir(p), ".template-"+ast.NewNodeID())

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Ensure the HTTP client sends the content as a UTF-8 JSON string (string escapes like \uXXXX are fine)
  2. Convert the source text to UTF-8 before writing, e.g. iconv or an encoding-aware reader in your script
  3. If writing from bytes in Go/Node, validate utf8.Valid(bytes) / Buffer.isUtf8(bytes) before embedding into the JSON payload

Example fix

// before (Go client)
content := string(rawGBKBytes)
req := TemplateFileRequest{Action: "write", Path: "t.md", Content: content}
// after
if !utf8.Valid(rawGBKBytes) { rawGBKBytes, _ = gbkToUTF8(rawGBKBytes) }
req := TemplateFileRequest{Action: "write", Path: "t.md", Content: string(rawGBKBytes)}
Defensive patterns

Strategy: validation

Validate before calling

const bytes = Buffer.from(content, 'utf8');
if (!Buffer.isUtf8(bytes)) {
  throw new Error('content is not valid UTF-8');
}

Try / catch

try {
  await manageTemplateFiles({ action: 'write', path: p, revision: rev, content });
} catch (e) {
  if (String(e.message).includes('invalid template source')) {
    // re-encode content from its source encoding to UTF-8 and retry
  }
}

Prevention

When it happens

Trigger: ManageTemplateFiles with action="write" where request.Content, after JSON decoding, contains invalid UTF-8 — typically when a client sends raw binary bytes or a string built from non-UTF-8 byte data instead of properly encoded text.

Common situations: A script POSTs file bytes read with the wrong encoding; a client library mangles multi-byte characters; an integration writes templates from a legacy-encoded source without converting first.

Related errors


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