{"record":{"id":"1fd6e4f4de2e6bf6","repo":"siyuan-note/siyuan","slug":"template-path-is-not-a-regular-file-or-directory","errorCode":null,"errorMessage":"template path is not a regular file or directory","messagePattern":"template path is not a regular file or directory","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/template_manage.go","lineNumber":112,"sourceCode":"\treturn os.OpenRoot(filepath.Join(util.DataDir, \"templates\"))\n}\n\n// 除根目录外不接受符号链接，避免管理操作影响另一个模板包。\nfunc checkTemplateFilePath(root *os.Root, p string) error {\n\tif err := validateTemplateRelativePath(p, false); err != nil {\n\t\treturn err\n\t}\n\tparts := strings.Split(p, \"/\")\n\tfor i := range parts {\n\t\tinfo, err := root.Lstat(strings.Join(parts[:i+1], \"/\"))\n\t\tif errors.Is(err, os.ErrNotExist) && i == len(parts)-1 {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif info.Mode()&os.ModeSymlink != 0 || (!info.IsDir() && !info.Mode().IsRegular()) {\n\t\t\treturn errors.New(\"template path is not a regular file or directory\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc templateFileRevision(root *os.Root, p string) (string, error) {\n\tinfo, err := root.Stat(p)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\th := sha256.New()\n\tif info.IsDir() {\n\t\terr = fs.WalkDir(root.FS(), p, func(name string, entry fs.DirEntry, walkErr error) error {\n\t\t\tif walkErr != nil {\n\t\t\t\treturn walkErr\n\t\t\t}\n\t\t\tstat, statErr := entry.Info()\n\t\t\tif statErr != nil {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/template_manage.go#L94-L130","documentation":"checkTemplateFilePath verified the filesystem entry at the template path and found it is neither a regular file nor a directory (or it is a symlink). Only plain files and directories are allowed so template content is read predictably and symlinks cannot escape the templates root.","triggerScenarios":"DocSaveAsTemplateInDirectory or ManageTemplateFilePath checks os.Lstat/stat of the path and finds info.Mode()&os.ModeSymlink != 0 or a non-regular, non-directory mode (device, pipe, socket, irregular file).","commonSituations":"A symlink planted inside the templates directory pointing outside the workspace; named pipes or device files created by other tooling; a broken path that resolved to something unexpected.","solutions":["Replace the symlink or special file with a real regular file/directory","Point the template path at an actual .md file or plain directory","Remove unexpected special files from the templates directory"],"exampleFix":"// before\n$ ln -s /etc/passwd templates/evil.md\n// after: use a real file\n$ rm templates/evil.md\n$ cp real-template.md templates/evil.md\n","handlingStrategy":"validation","validationCode":"info, err := os.Lstat(p)\nif err != nil || info.Mode()&os.ModeSymlink != 0 || (!info.IsDir() && !info.Mode().IsRegular()) {\n    return errors.New(\"path must be a regular file or directory, not a symlink\")\n}","typeGuard":null,"tryCatchPattern":"if err := checkTemplateFilePath(root, p); err != nil {\n    return fmt.Errorf(\"template path unusable: %w\", err)\n}","preventionTips":["Do not place symlinks in the templates directory","Create templates as plain .md files or plain directories","Audit the templates dir for special files after syncing from other systems"],"tags":["template","filesystem","symlink"],"backgroundTag":"path-traversal-blocked","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}