siyuan-note/siyuan · error

content template [%s] is not a regular file

Error message

content template [%s] is not a regular file

What it means

Returned by resolveDocContentTemplatePath (template.go:730) when, after resolving symlinks with filepath.EvalSymlinks, os.Stat reports the target is NOT a regular file (info.Mode().IsRegular() is false, or stat itself errored). Guards against templates pointing at directories, devices, pipes, or sockets.

Source

Thrown at kernel/model/template.go:730

	templateRoot := filepath.Join(util.DataDir, "templates")
	absPath := filepath.Join(templateRoot, cleanPath)
	if !gulu.File.IsSubPath(templateRoot, absPath) {
		return "", errors.New("content template path is outside templates directory")
	}
	if !filelock.IsExist(absPath) {
		return "", fmt.Errorf("content template [%s] not found", templatePath)
	}
	realRoot, err := filepath.EvalSymlinks(templateRoot)
	if nil != err {
		return "", err
	}
	realPath, err := filepath.EvalSymlinks(absPath)
	if nil != err {
		return "", err
	}
	info, err := os.Stat(realPath)
	if nil != err || !info.Mode().IsRegular() {
		return "", fmt.Errorf("content template [%s] is not a regular file", templatePath)
	}
	if !gulu.File.IsSubPath(realRoot, realPath) {
		return "", errors.New("content template path is outside templates directory")
	}
	return realPath, nil
}

// CreateTemplate 在 <data>/templates/ 下创建模板文件。name 不含扩展名,content 为 markdown 文本。
// overwrite=false 且文件已存在时返回 code=1(与 DocSaveAsTemplate 一致)。
func CreateTemplate(name, content string, overwrite bool) (code int, err error) {
	name = util.FilterFileName(name) + ".md"
	name = util.TruncateLenFileName(name)
	savePath := filepath.Join(util.DataDir, "templates", name)
	if filelock.IsExist(savePath) {
		if !overwrite {
			code = 1
			return
		}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Point the content template path at a specific .md FILE, not a directory.
  2. If using a symlink, ensure the symlink target is a regular markdown file.
  3. Check filesystem permissions on the target file; the SiYuan process must be able to stat it.
  4. Replace any accidental directory/special-file path with a real template file.

Example fix

// before — path is a directory
resolveDocContentTemplatePath("subfolder")

// after — path is a regular file
resolveDocContentTemplatePath("subfolder/tpl.md")
Defensive patterns

Strategy: validation

Validate before calling

import "os"
import "path/filepath"

func templateIsRegularFile(p string) bool {
    abs := filepath.Join(util.DataDir, "templates", filepath.Clean(filepath.FromSlash(p)))
    real, err := filepath.EvalSymlinks(abs)
    if err != nil { return false }
    info, err := os.Stat(real)
    if err != nil { return false }
    return info.Mode().IsRegular()
}

Prevention

When it happens

Trigger: The template path resolves to a directory, a named pipe, a device node, or a broken symlink target; os.Stat fails entirely (permission denied). EvalSymlinks succeeded (so the link chain resolves) but the terminal inode is not a regular file.

Common situations: A user accidentally points the content template at a directory (e.g. a templates subfolder rather than a .md file); a symlink points to a special file; filesystem corruption; permission issues preventing stat.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/59ce1684485701f5. Report an issue: GitHub.