siyuan-note/siyuan · error
template directory contains a symbolic link
Error message
template directory contains a symbolic link
What it means
While hashing a template directory (computing a manifest over its entries), a directory entry was found to be a symbolic link. Template directories must contain only regular entries; symlinks are refused so the manifest/hash reflects only real contained data and cannot be used to reach outside the directory.
Source
Thrown at kernel/model/template_manage.go:134
}
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 {
return statErr
}
if stat.Mode()&os.ModeSymlink != 0 {
return errors.New("template directory contains a symbolic link")
}
fmt.Fprintf(h, "%s\x00%d\x00%d\x00%d\n", name, stat.Size(), stat.ModTime().UnixNano(), stat.Mode())
return nil
})
} else {
if info.Size() > maxTemplateSourceSize {
return "", errors.New("template source is too large")
}
var content []byte
content, err = root.ReadFile(p)
h.Write(content)
}
return fmt.Sprintf("%x", h.Sum(nil)), err
}
func readTemplateSource(root *os.Root, p string) (string, error) {
info, err := root.Stat(p)
if err != nil {View on GitHub (pinned to 8641553a1f)
Solutions
- Remove or replace the symlink inside the template directory with a real file/directory
- Rescan after cleaning; the hash/manifest will then succeed
- Keep symlinks out of directories managed as template packages
Example fix
// before $ ln -s ../shared/theme.css templates/pkg/theme.css // after $ rm templates/pkg/theme.css $ cp ../shared/theme.css templates/pkg/theme.css
Defensive patterns
Strategy: validation
Validate before calling
func dirHasSymlinks(dir string) (bool, error) {
found := false
err := filepath.WalkDir(dir, func(_ string, d fs.DirEntry, err error) error {
if err != nil { return err }
if d.Type()&fs.ModeSymlink != 0 { found = true }
return nil
})
return found, err
}
// refuse to use the directory if dirHasSymlinks returns true Try / catch
if err := hashTemplateDir(root, p, h); err != nil {
return fmt.Errorf("template dir must be symlink-free: %w", err)
} Prevention
- Keep managed template directories free of symlinks
- Copy real files instead of linking when assembling template packages
- Re-check directories after sync tools or archives may have introduced links
When it happens
Trigger: The template-directory hash/manifest walk calls entry.Info() on each child and stat.Mode()&os.ModeSymlink != 0, e.g. a symlinked file or subdirectory placed inside a managed template package directory.
Common situations: Symlinks inside shared/synced template folders (e.g. created on macOS/Linux then surfaced elsewhere); maliciously planted symlinks; build tooling leaving link artifacts in the template directory.
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
- template path is not a regular file or directory
- asset path contains an unresolved symbolic link [%s]
- resolve assets directory [%s] failed: %w
- encrypted document is a symbolic link [%s]
- exporting symbolic links is not supported
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/a94aabe9a0663313.
Report an issue: GitHub.