siyuan-note/siyuan · error

template path is not a regular file or directory

Error message

template path is not a regular file or directory

What it means

checkTemplateFilePath verified the filesystem entry at the template path and found it is neither a regular file nor a directory (or it is a symlink). Only plain files and directories are allowed so template content is read predictably and symlinks cannot escape the templates root.

Source

Thrown at kernel/model/template_manage.go:112

	return os.OpenRoot(filepath.Join(util.DataDir, "templates"))
}

// 除根目录外不接受符号链接,避免管理操作影响另一个模板包。
func checkTemplateFilePath(root *os.Root, p string) error {
	if err := validateTemplateRelativePath(p, false); err != nil {
		return err
	}
	parts := strings.Split(p, "/")
	for i := range parts {
		info, err := root.Lstat(strings.Join(parts[:i+1], "/"))
		if errors.Is(err, os.ErrNotExist) && i == len(parts)-1 {
			return nil
		}
		if err != nil {
			return err
		}
		if info.Mode()&os.ModeSymlink != 0 || (!info.IsDir() && !info.Mode().IsRegular()) {
			return errors.New("template path is not a regular file or directory")
		}
	}
	return nil
}

func templateFileRevision(root *os.Root, p string) (string, error) {
	info, err := root.Stat(p)
	if err != nil {
		return "", err
	}
	h := sha256.New()
	if info.IsDir() {
		err = fs.WalkDir(root.FS(), p, func(name string, entry fs.DirEntry, walkErr error) error {
			if walkErr != nil {
				return walkErr
			}
			stat, statErr := entry.Info()
			if statErr != nil {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Replace the symlink or special file with a real regular file/directory
  2. Point the template path at an actual .md file or plain directory
  3. Remove unexpected special files from the templates directory

Example fix

// before
$ ln -s /etc/passwd templates/evil.md
// after: use a real file
$ rm templates/evil.md
$ cp real-template.md templates/evil.md
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Lstat(p)
if err != nil || info.Mode()&os.ModeSymlink != 0 || (!info.IsDir() && !info.Mode().IsRegular()) {
    return errors.New("path must be a regular file or directory, not a symlink")
}

Try / catch

if err := checkTemplateFilePath(root, p); err != nil {
    return fmt.Errorf("template path unusable: %w", err)
}

Prevention

When it happens

Trigger: DocSaveAsTemplateInDirectory or ManageTemplateFilePath checks os.Lstat/stat of the path and finds info.Mode()&os.ModeSymlink != 0 or a non-regular, non-directory mode (device, pipe, socket, irregular file).

Common situations: A symlink planted inside the templates directory pointing outside the workspace; named pipes or device files created by other tooling; a broken path that resolved to something unexpected.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


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