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

  1. Generate IDs the same way SiYuan mints block IDs (20 lowercase hex chars).
  2. Reuse the frontend's ID generator rather than inventing a scheme.
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/4edfd2b95edeabe2. Report an issue: GitHub.