siyuan-note/siyuan · error
template path is outside templates directory
Error message
template path is outside templates directory
What it means
resolveTemplatePackageFile computes the root template's location relative to the templates directory (data/templates). If filepath.Rel fails or the root template path resolves outside that directory, the error is thrown. Only templates stored under data/templates may act as package roots for child-template resolution.
Source
Thrown at kernel/model/template_doc_tree.go:407
templateDocTreePlans.Store(id, plan)
templateDocTreePlansLock.Unlock()
time.AfterFunc(templateDocTreePlanTTL, func() {
templateDocTreePlans.Delete(id)
})
return collector.summary(id)
}
func resolveTemplatePackageFile(rootTemplatePath, relativePath string) (string, error) {
relativePath = strings.TrimPrefix(filepath.ToSlash(strings.TrimSpace(relativePath)), "/")
cleanPath := filepath.Clean(filepath.FromSlash(relativePath))
if "" == cleanPath || "." == cleanPath || filepath.IsAbs(cleanPath) || ".." == cleanPath ||
strings.HasPrefix(cleanPath, ".."+string(os.PathSeparator)) {
return "", errors.New("invalid child template path")
}
templatesRoot := filepath.Clean(filepath.Join(util.DataDir, "templates"))
relRootTemplate, err := filepath.Rel(templatesRoot, filepath.Clean(rootTemplatePath))
if nil != err || strings.HasPrefix(relRootTemplate, ".."+string(os.PathSeparator)) {
return "", errors.New("template path is outside templates directory")
}
parts := strings.Split(filepath.ToSlash(relRootTemplate), "/")
packageRoot := templatesRoot
if 1 < len(parts) {
packageRoot = filepath.Join(templatesRoot, parts[0])
}
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
}View on GitHub (pinned to 8641553a1f)
Solutions
- Move the template package into data/templates/ (SiYuan - Documents folder/templates) and reference it from there
- If using a symlink, ensure its resolved target is still inside data/templates
- Check the template path resolution logic: the root template must be at data/templates/<pkg>/... or data/templates/<file>
- Re-download or reinstall the template from the marketplace if it was installed to an unexpected location
Example fix
// before: root template resolved outside the templates root rootTemplatePath := filepath.Join(util.DataDir, "mytpl", "index.tpl") // after rootTemplatePath := filepath.Join(util.DataDir, "templates", "mytpl", "index.tpl")
Defensive patterns
Strategy: validation
Validate before calling
// Go: ensure the root template lives under data/templates before rendering root := filepath.Clean(rootTemplatePath) templatesRoot := filepath.Clean(filepath.Join(util.DataDir, "templates")) rel, err := filepath.Rel(templatesRoot, root) safe := err == nil && !strings.HasPrefix(rel, ".."+string(os.PathSeparator))
Try / catch
if _, err := resolveTemplatePackageFile(rootPath, rel); err != nil && strings.Contains(err.Error(), "outside templates directory") {
return relocateTemplateToDataDir(rootPath)
} Prevention
- Install all templates under <workspace>/data/templates/
- Avoid symlinking template directories to locations outside data/templates
- Use the built-in template install/marketplace flow rather than manual file placement
- After workspace migration, verify template files moved into data/templates
When it happens
Trigger: Rendering a template whose root .md/.tpl file is not under util.DataDir/templates — e.g. a path under data/ directly, a symlink target outside the templates dir, or a custom template location passed to renderTemplateDocTreeNodeContent.
Common situations: Manually placing template files outside data/templates and referencing them; a symlinked templates directory whose real target lies elsewhere; copying a template into data/ root instead of data/templates; older workspaces where the templates folder was relocated.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid child template path
- document path [%s] already exists
- child template [%s] not found in the current template packag
- child template [%s] is not a regular file
- child template path is outside the current template package
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/5d267e6cd72f6db6.
Report an issue: GitHub.