siyuan-note/siyuan · error
invalid new item template id [%s]
Error message
invalid new item template id [%s]
What it means
itemTemplate.ID must satisfy ast.IsNodeIDPattern — the SiYuan block-ID format (a 20-character lowercase hex timestamp-prefixed identifier). Template IDs are persisted and referenced by DefaultTemplateID, so they must follow the same scheme as every other node ID in the workspace.
Source
Thrown at kernel/av/new_item_template.go:67
}
itemTemplate = cloneNewItemTemplate(itemTemplate)
if nil == itemTemplate {
return errors.New("clone new item template failed")
}
itemTemplate.Name = strings.TrimSpace(itemTemplate.Name)
itemTemplate.Icon = strings.TrimSpace(itemTemplate.Icon)
if filteredIcon, valid := util.FilterIconValue(itemTemplate.Icon); valid {
itemTemplate.Icon = filteredIcon
} else {
// 非法图标值置空,防止存储可执行标记
// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-vx5w-qrvp-mmcq
itemTemplate.Icon = ""
}
if "" == itemTemplate.Name {
return errors.New("new item template name is empty")
}
if !ast.IsNodeIDPattern(itemTemplate.ID) {
return fmt.Errorf("invalid new item template id [%s]", itemTemplate.ID)
}
if templateIDs[itemTemplate.ID] {
return fmt.Errorf("duplicated new item template id [%s]", itemTemplate.ID)
}
templateIDs[itemTemplate.ID] = true
if NewItemTargetDetached != itemTemplate.TargetType && NewItemTargetDocument != itemTemplate.TargetType {
return fmt.Errorf("invalid new item template target type [%s]", itemTemplate.TargetType)
}
if NewItemTargetDocument != itemTemplate.TargetType {
itemTemplate.Icon = ""
itemTemplate.HideInFileTree = false
}
itemTemplate.ContentTemplatePath = strings.TrimSpace(itemTemplate.ContentTemplatePath)
if nil != itemTemplate.SaveLocation {
itemTemplate.SaveLocation.BoxID = strings.TrimSpace(itemTemplate.SaveLocation.BoxID)
itemTemplate.SaveLocation.PathTemplate = strings.TrimSpace(itemTemplate.SaveLocation.PathTemplate)
}
if err := av.normalizeNewItemTemplateFieldValues(itemTemplate); nil != err {View on GitHub (pinned to 251596fc0d)
Solutions
- Generate IDs the same way SiYuan mints block IDs (20 lowercase hex chars).
- Reuse the frontend's ID generator rather than inventing a scheme.
- If scripting, call the kernel's exposed ID-generation helper instead of hardcoding.
Example fix
// before
&av.NewItemTemplate{ID: "tpl1"}
// after
&av.NewItemTemplate{ID: "20240812120000abcde123"} Defensive patterns
Strategy: validation
Validate before calling
import "github.com/88250/lute/ast"
if !ast.IsNodeIDPattern(t.ID) {
return fmt.Errorf("invalid new item template id [%s]", t.ID)
} Type guard
func isValidTemplateID(id string) bool {
return ast.IsNodeIDPattern(id) // 20-char lowercase hex
} Prevention
- Generate IDs with the same algorithm SiYuan uses for block IDs.
- Never hardcode short or uppercase identifiers in template payloads.
- Validate IDs at the form boundary before reaching the kernel.
When it happens
Trigger: Frontend sends a short, uppercase, or non-hex ID; manual API/script call with an arbitrary string; version skew where the client uses an old ID generator.
Common situations: SDK or test harness minting IDs like 'tpl-1'; stale frontend build; data corruption after a failed sync.
Related errors
- new item templates config is nil
- new item template name is empty
- duplicated new item template id [%s]
- invalid new item template target type [%s]
- default new item template [%s] not found
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/4edfd2b95edeabe2.
Report an issue: GitHub.