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

  1. Move the template package into data/templates/ (SiYuan - Documents folder/templates) and reference it from there
  2. If using a symlink, ensure its resolved target is still inside data/templates
  3. Check the template path resolution logic: the root template must be at data/templates/<pkg>/... or data/templates/<file>
  4. 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

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


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