siyuan-note/siyuan · error
invalid template path component
Error message
invalid template path component
What it means
validateNewTemplateName rejects a template name component that starts with a dot, has leading/trailing whitespace, ends with a dot, contains reserved characters (\\ : < > \" | ? *), or contains control characters. The base name must be a safe, cross-platform file name component.
Source
Thrown at kernel/model/template_manage.go:79
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
}
// 清单与目录共同标识模板包,保留目录身份以维持搜索和集市更新。
func isManagedTemplatePackage(root *os.Root, p string) bool {
_, err := root.Lstat(path.Join(p, "template.json"))
return err == nil
}
func openTemplateRoot() (*os.Root, error) {
if err := os.MkdirAll(filepath.Join(util.DataDir, "templates"), 0755); err != nil {
return nil, err
}
return os.OpenRoot(filepath.Join(util.DataDir, "templates"))
}
// 除根目录外不接受符号链接,避免管理操作影响另一个模板包。View on GitHub (pinned to 8641553a1f)
Solutions
- Trim whitespace and remove reserved characters (\\ : < > \" | ? *) and control chars from the name
- Strip leading dots and trailing dots from the component
- Sanitize names in the UI before submission
Example fix
// before
name := "my: report?.md"
err := validateNewTemplateName(name) // fails
// after
name := sanitize(strings.TrimSpace("my: report?.md")) // "my report.md"
err := validateNewTemplateName(name)
Defensive patterns
Strategy: validation
Validate before calling
func validTemplateComponent(name string) bool {
base := path.Base(name)
return !strings.HasPrefix(base, ".") && strings.TrimSpace(base) == base &&
!strings.HasSuffix(base, ".") && !strings.ContainsAny(base, "\\:<>\"|?*") &&
!strings.ContainsFunc(base, unicode.IsControl)
} Try / catch
if !validTemplateComponent(newName) {
return fmt.Errorf("sanitize name %q before creating template", newName)
}
if err := validateNewTemplateName(newName); err != nil { return err } Prevention
- Trim and sanitize template names before submission
- Strip reserved characters (\\ : < > \" | ? *) and control bytes
- Avoid leading/trailing dots and whitespace in names
When it happens
Trigger: ManageTemplateFiles calls validateNewTemplateName with a name like "my template .md", "a<b>.md", "tpl?.md", or a name with trailing spaces or embedded control characters.
Common situations: User-typed names copied from Windows Explorer with illegal characters; paste of strings with invisible control bytes; names with trailing periods or spaces (invalid on Windows).
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
- template source must use the .md extension
- custom emoji name must not be empty
- invalid custom emoji name
- path is required
- Conf.Language(37)
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/ec46a47b58a68522.
Report an issue: GitHub.