siyuan-note/siyuan · error
child template path is outside the current template package
Error message
child template path is outside the current template package
What it means
As the final defense, resolveTemplatePackageFile re-checks the fully resolved (symlink-followed) real path against the resolved package root with gulu.File.IsSubPath. If EvalSymlinks revealed that the file physically lives outside the template package — even though the lexical path was inside — resolution is rejected. This closes the symlink-escape hole after the earlier lexical and existence checks.
Source
Thrown at kernel/model/template_doc_tree.go:431
}
absPath := filepath.Join(packageRoot, cleanPath)
if !gulu.File.IsSubPath(packageRoot, absPath) || !filelock.IsExist(absPath) {
return "", fmt.Errorf("child template [%s] not found in the current template package", relativePath)
}
realRoot, err := filepath.EvalSymlinks(packageRoot)
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("child template [%s] is not a regular file", relativePath)
}
if !gulu.File.IsSubPath(realRoot, realPath) {
return "", errors.New("child template path is outside the current template package")
}
return realPath, nil
}
func templateDocTreeDataModel(node *TemplateDocTreeNode) map[string]string {
return map[string]string{
"title": node.Title,
"id": node.ID,
"parentID": node.ParentID,
"rootID": node.RootID,
"hPath": node.HPath,
"name": "",
"alias": "",
}
}
// AttachTemplateDocTreePlans 将一次性计划转换为内核事务操作,父文档内容与全部子文档共用一条撤销记录。
func AttachTemplateDocTreePlans(transactions []*Transaction) (attached bool, err error) {View on GitHub (pinned to 8641553a1f)
Solutions
- Replace the symlink with a real copy of the target file inside the template package
- Move the shared partial into the package and update references to use the local path
- If the shared content belongs to another package, keep each package self-contained and duplicate the partial
- Verify with a filesystem check that all files under data/templates/<pkg> are regular files physically located within the package
Example fix
# before: symlink escaping the package ln -s ../../shared/header.md data/templates/mypkg/header.md # after: physical copy inside the package cp ../../shared/header.md data/templates/mypkg/header.md
Defensive patterns
Strategy: validation
Validate before calling
// Go: detect symlink escapes in a template package before use
filepath.Walk(pkgRoot, func(p string, info os.FileInfo, err error) error {
if info.Mode()&os.ModeSymlink != 0 {
real, _ := filepath.EvalSymlinks(p)
if ok, _ := gulu.File.IsSubPath(pkgRoot, real); !ok {
return fmt.Errorf("symlink escape: %s -> %s", p, real)
}
}
return nil
}) Try / catch
path, err := resolveTemplatePackageFile(root, rel)
if err != nil && strings.Contains(err.Error(), "outside the current template package") {
return fmt.Errorf("%q is a symlink pointing outside the package; copy the file in", rel)
} Prevention
- Never symlink shared partials across template packages — copy them instead
- Audit packages for symlinks before installing from untrusted sources
- Keep each template package fully self-contained on disk
- Prefer hard copies or package-local includes when sharing common fragments
When it happens
Trigger: A file inside data/templates/<pkg>/ is a symlink whose target lies outside the package (e.g. ../../other-package/shared.tpl or an absolute path elsewhere on disk), and a template references it as a child template.
Common situations: Users symlinking shared partials between template packages to avoid duplication; package managers that deduplicate files via symlinks; dotfile-style setups where the templates dir contains links into a personal notes repo.
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
- path escapes templates dir: %s
- symlink escapes workspace: %s
- path escapes templates dir: %s
- notebook asset path resolves outside notebook directory: %s
- asset path resolves outside assets directory: %s
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/ec7d22c70c32f69d.
Report an issue: GitHub.