{"record":{"id":"4edfd2b95edeabe2","repo":"siyuan-note/siyuan","slug":"invalid-new-item-template-id-s","errorCode":null,"errorMessage":"invalid new item template id [%s]","messagePattern":"invalid new item template id \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/av/new_item_template.go","lineNumber":67,"sourceCode":"\t\t}\n\t\titemTemplate = cloneNewItemTemplate(itemTemplate)\n\t\tif nil == itemTemplate {\n\t\t\treturn errors.New(\"clone new item template failed\")\n\t\t}\n\t\titemTemplate.Name = strings.TrimSpace(itemTemplate.Name)\n\t\titemTemplate.Icon = strings.TrimSpace(itemTemplate.Icon)\n\t\tif filteredIcon, valid := util.FilterIconValue(itemTemplate.Icon); valid {\n\t\t\titemTemplate.Icon = filteredIcon\n\t\t} else {\n\t\t\t// 非法图标值置空，防止存储可执行标记\n\t\t\t// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-vx5w-qrvp-mmcq\n\t\t\titemTemplate.Icon = \"\"\n\t\t}\n\t\tif \"\" == itemTemplate.Name {\n\t\t\treturn errors.New(\"new item template name is empty\")\n\t\t}\n\t\tif !ast.IsNodeIDPattern(itemTemplate.ID) {\n\t\t\treturn fmt.Errorf(\"invalid new item template id [%s]\", itemTemplate.ID)\n\t\t}\n\t\tif templateIDs[itemTemplate.ID] {\n\t\t\treturn fmt.Errorf(\"duplicated new item template id [%s]\", itemTemplate.ID)\n\t\t}\n\t\ttemplateIDs[itemTemplate.ID] = true\n\t\tif NewItemTargetDetached != itemTemplate.TargetType && NewItemTargetDocument != itemTemplate.TargetType {\n\t\t\treturn fmt.Errorf(\"invalid new item template target type [%s]\", itemTemplate.TargetType)\n\t\t}\n\t\tif NewItemTargetDocument != itemTemplate.TargetType {\n\t\t\titemTemplate.Icon = \"\"\n\t\t\titemTemplate.HideInFileTree = false\n\t\t}\n\t\titemTemplate.ContentTemplatePath = strings.TrimSpace(itemTemplate.ContentTemplatePath)\n\t\tif nil != itemTemplate.SaveLocation {\n\t\t\titemTemplate.SaveLocation.BoxID = strings.TrimSpace(itemTemplate.SaveLocation.BoxID)\n\t\t\titemTemplate.SaveLocation.PathTemplate = strings.TrimSpace(itemTemplate.SaveLocation.PathTemplate)\n\t\t}\n\t\tif err := av.normalizeNewItemTemplateFieldValues(itemTemplate); nil != err {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/av/new_item_template.go#L49-L85","documentation":"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.","triggerScenarios":"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.","commonSituations":"SDK or test harness minting IDs like 'tpl-1'; stale frontend build; data corruption after a failed sync.","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."],"exampleFix":"// before\n&av.NewItemTemplate{ID: \"tpl1\"}\n// after\n&av.NewItemTemplate{ID: \"20240812120000abcde123\"}","handlingStrategy":"validation","validationCode":"import \"github.com/88250/lute/ast\"\n\nif !ast.IsNodeIDPattern(t.ID) {\n    return fmt.Errorf(\"invalid new item template id [%s]\", t.ID)\n}","typeGuard":"func isValidTemplateID(id string) bool {\n    return ast.IsNodeIDPattern(id) // 20-char lowercase hex\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["av","new-item-template","node-id","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}