siyuan-note/siyuan · error
invalid template path
Error message
invalid template path
What it means
validateTemplateRelativePath rejected the given template relative path because it is empty when a root path is not allowed, is not a valid fs.ValidPath, or contains forbidden characters (backslash, colon, NUL). This guards against malformed and unsafe paths before any file access.
Source
Thrown at kernel/model/template_manage.go:61
Path string `json:"path"`
Target string `json:"target"`
Content string `json:"content"`
Revision string `json:"revision"`
}
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")View on GitHub (pinned to 8641553a1f)
Solutions
- Convert the path to slash-separated relative form (strip volume/drive prefixes and leading separators)
- Clean the path with path.Clean / fs.ValidPath semantics before calling
- Reject or sanitize user input before constructing the template path
Example fix
// before
err := validateTemplateRelativePath("C:\\templates\\foo.md", false)
// after
p := path.Clean(strings.ReplaceAll(userPath, "\\", "/"))
p = strings.TrimPrefix(p, "/")
err := validateTemplateRelativePath(p, false)
Defensive patterns
Strategy: validation
Validate before calling
func safeTemplatePath(p string) bool {
return p != "" && fs.ValidPath(p) && !strings.ContainsAny(p, "\\:\x00")
} Try / catch
if err := validateTemplateRelativePath(p, false); err != nil {
return fmt.Errorf("rejecting bad template path %q: %w", p, err)
} Prevention
- Always pass slash-separated relative paths, never absolute or Windows paths
- Run path.Clean and strip leading separators before calling
- Reject user input containing backslash, colon, or NUL
When it happens
Trigger: DocSaveAsTemplateInDirectory or checkTemplateFilePath calls validateTemplateRelativePath with a path containing "\\", ":", or "\x00", or a path failing fs.ValidPath (e.g. leading/trailing slash, ".", "..", empty segments).
Common situations: Windows-style separators (\\) passed on any platform; absolute paths passed where a relative path is required; user-supplied paths containing colons (e.g. drive letters) or NUL bytes.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid content template path
- --path is required
- invalid path
- path is required
- asset path must be absolute
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/de0a29d0ab7cec1d.
Report an issue: GitHub.