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
- Point the content template path at a specific .md FILE, not a directory.
- If using a symlink, ensure the symlink target is a regular markdown file.
- Check filesystem permissions on the target file; the SiYuan process must be able to stat it.
- 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
- Point content template paths at .md files, never directories or special files.
- Ensure symlinks resolve to regular files.
- Check filesystem permissions allow stat.
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
- import path is not sub path of import dir
- path escapes templates dir: %s
- path [%s] must not contain '..'
- path [%s] escapes box directory
- path is not a child of assets directory: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/59ce1684485701f5.
Report an issue: GitHub.