{"record":{"id":"5d267e6cd72f6db6","repo":"siyuan-note/siyuan","slug":"template-path-is-outside-templates-directory-5d267e","errorCode":null,"errorMessage":"template path is outside templates directory","messagePattern":"template path is outside templates directory","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_doc_tree.go","lineNumber":407,"sourceCode":"\ttemplateDocTreePlans.Store(id, plan)\n\ttemplateDocTreePlansLock.Unlock()\n\ttime.AfterFunc(templateDocTreePlanTTL, func() {\n\t\ttemplateDocTreePlans.Delete(id)\n\t})\n\treturn collector.summary(id)\n}\n\nfunc resolveTemplatePackageFile(rootTemplatePath, relativePath string) (string, error) {\n\trelativePath = strings.TrimPrefix(filepath.ToSlash(strings.TrimSpace(relativePath)), \"/\")\n\tcleanPath := filepath.Clean(filepath.FromSlash(relativePath))\n\tif \"\" == cleanPath || \".\" == cleanPath || filepath.IsAbs(cleanPath) || \"..\" == cleanPath ||\n\t\tstrings.HasPrefix(cleanPath, \"..\"+string(os.PathSeparator)) {\n\t\treturn \"\", errors.New(\"invalid child template path\")\n\t}\n\ttemplatesRoot := filepath.Clean(filepath.Join(util.DataDir, \"templates\"))\n\trelRootTemplate, err := filepath.Rel(templatesRoot, filepath.Clean(rootTemplatePath))\n\tif nil != err || strings.HasPrefix(relRootTemplate, \"..\"+string(os.PathSeparator)) {\n\t\treturn \"\", errors.New(\"template path is outside templates directory\")\n\t}\n\tparts := strings.Split(filepath.ToSlash(relRootTemplate), \"/\")\n\tpackageRoot := templatesRoot\n\tif 1 < len(parts) {\n\t\tpackageRoot = filepath.Join(templatesRoot, parts[0])\n\t}\n\tabsPath := filepath.Join(packageRoot, cleanPath)\n\tif !gulu.File.IsSubPath(packageRoot, absPath) || !filelock.IsExist(absPath) {\n\t\treturn \"\", fmt.Errorf(\"child template [%s] not found in the current template package\", relativePath)\n\t}\n\trealRoot, err := filepath.EvalSymlinks(packageRoot)\n\tif nil != err {\n\t\treturn \"\", err\n\t}\n\trealPath, err := filepath.EvalSymlinks(absPath)\n\tif nil != err {\n\t\treturn \"\", err\n\t}","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_doc_tree.go#L389-L425","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: root template resolved outside the templates root\nrootTemplatePath := filepath.Join(util.DataDir, \"mytpl\", \"index.tpl\")\n// after\nrootTemplatePath := filepath.Join(util.DataDir, \"templates\", \"mytpl\", \"index.tpl\")","handlingStrategy":"validation","validationCode":"// Go: ensure the root template lives under data/templates before rendering\nroot := filepath.Clean(rootTemplatePath)\ntemplatesRoot := filepath.Clean(filepath.Join(util.DataDir, \"templates\"))\nrel, err := filepath.Rel(templatesRoot, root)\nsafe := err == nil && !strings.HasPrefix(rel, \"..\"+string(os.PathSeparator))","typeGuard":null,"tryCatchPattern":"if _, err := resolveTemplatePackageFile(rootPath, rel); err != nil && strings.Contains(err.Error(), \"outside templates directory\") {\n    return relocateTemplateToDataDir(rootPath)\n}","preventionTips":["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"],"tags":["template","path-validation","templates-directory","siyuan-kernel"],"backgroundTag":"invalid-argument-value","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}