siyuan-note/siyuan · error

content template [ ] is not a regular file

Error message

content template [%s] is not a regular file

What it means

After resolving symlinks, resolveDocContentTemplatePath stats the real path and requires it to be a regular file (os.Stat + Mode().IsRegular()). This same error is also returned when os.Stat itself fails. Directories, devices, fifos, or broken entries under templates/ cannot be used as content templates.

Solutions

  1. Point templatePath at a regular .md file, not a directory or special file.
  2. Re-create the symlink or restore the missing target file, then retry.
  3. Check os.Stat manually on <data>/templates/<templatePath> to see whether it exists and what kind of entry it is.

Example fix

// before
templatePath := "templates-dir" // a directory
// after
templatePath := "templates-dir/index.md"
Defensive patterns

Strategy: validation

Validate before calling

const st = fs.statSync(process.env.SIYUAN_DATA + "/templates/" + templatePath);
if (!st.isFile()) throw new Error("template path is not a regular file");

Try / catch

try {
  await applyDocContentTemplate(boxID, templatePath);
} catch (e) {
  if (String(e).includes("not a regular file")) {
    // fall back to directory listing or ask user to select a file
  } else { throw e; }
}

Prevention

When it happens

Trigger: Passing a directory name inside <data>/templates/ as templatePath; the path is a symlink whose target vanished (EvalSymlinks succeeded but Stat failed), or the file was deleted between checks; the entry is a special file.

Common situations: Selecting a template subfolder instead of a file; symlinked template directories whose target was unmounted; race where the file is removed while the template is being applied.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/59ce1684485701f5. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/template.go:1240

	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 9f775e8a12)