siyuan-note/siyuan · error
hidden template paths are reserved
Error message
hidden template paths are reserved
What it means
Any path segment of the template relative path starting with a dot is rejected as reserved for hidden entries. Hidden files/directories are excluded from the template namespace to avoid colliding with metadata or dotfiles on any platform.
Source
Thrown at kernel/model/template_manage.go:65
}
type TemplateFileEntry struct {
Path string `json:"path"`
IsDir bool `json:"isDir"`
IsPackage bool `json:"isPackage,omitempty"`
}
// 访问已有模板只校验目录边界,不对文件名进行清理或改写。
func validateTemplateRelativePath(p string, allowRoot bool) error {
if p == "" && allowRoot {
return nil
}
if p == "" || !fs.ValidPath(p) || strings.ContainsAny(p, "\\:\x00") {
return errors.New("invalid template path")
}
for _, part := range strings.Split(p, "/") {
if strings.HasPrefix(part, ".") {
return errors.New("hidden template paths are reserved")
}
}
return nil
}
// 新名称保持跨平台可用,已有父目录沿用原名。
func validateNewTemplateName(p string) error {
part := path.Base(p)
device := strings.ToUpper(strings.SplitN(part, ".", 2)[0])
if device == "CON" || device == "PRN" || device == "AUX" || device == "NUL" || (len(device) == 4 && (strings.HasPrefix(device, "COM") || strings.HasPrefix(device, "LPT")) && device[3] >= '1' && device[3] <= '9') {
return errors.New("reserved template file name")
}
if strings.HasPrefix(part, ".") || strings.TrimSpace(part) != part || strings.HasSuffix(part, ".") || strings.ContainsAny(part, "\\:<>\"|?*") || strings.ContainsFunc(part, unicode.IsControl) {
return errors.New("invalid template path component")
}
return nil
}
View on GitHub (pinned to 8641553a1f)
Solutions
- Remove or rename the dot-prefixed segment so no path part starts with "."
- Store templates in normal (non-hidden) directories
- Filter out dotfiles before iterating template candidates
Example fix
// before
err := validateTemplateRelativePath(".hidden/tpl.md", false)
// after
err := validateTemplateRelativePath("templates/tpl.md", false)
Defensive patterns
Strategy: validation
Validate before calling
func hasHiddenSegment(p string) bool {
for _, part := range strings.Split(p, "/") {
if strings.HasPrefix(part, ".") { return true }
}
return false
}
// reject before calling: hasHiddenSegment(p) Try / catch
if hasHiddenSegment(p) {
return errors.New("template paths must not contain hidden (dot-prefixed) segments")
}
if err := validateTemplateRelativePath(p, false); err != nil { return err } Prevention
- Avoid dot-prefixed files/directories in the template tree
- Skip hidden files when iterating template candidates
- Educate users that templates live in normal visible directories
When it happens
Trigger: validateTemplateRelativePath (via DocSaveAsTemplateInDirectory or checkTemplateFilePath) receives a path where strings.HasPrefix(part, ".") for some segment, e.g. ".config/tpl.md" or "notes/.hidden.md".
Common situations: Users trying to store templates in a dot-directory; hidden temp files (e.g. ".DS_Store", editor swap files) being passed as template paths; programmatic paths built from hidden config dirs.
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 is required
- invalid content template path
- content template path is outside templates directory
- content template [%s] not found
- content template [%s] is not a regular file
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/b57032e36b49f06d.
Report an issue: GitHub.