{"record":{"id":"a7fa1e47397ed381","repo":"siyuan-note/siyuan","slug":"conf-language-25-node-id","errorCode":null,"errorMessage":"Conf.Language(25) + \" [\" + node.ID + \"]\"","messagePattern":"Conf\\.Language\\(25\\) \\+ \" \\[\" \\+ node\\.ID \\+ \"\\]\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/blockial.go","lineNumber":390,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\toldAttrs = parse.IAL2Map(node.KramdownIAL)\n\tnewAttrsUnEsc := parse.IAL2MapUnEsc(node.KramdownIAL)\n\tfor name := range nameValues {\n\t\tif \"fold\" == strings.ToLower(name) {\n\t\t\tdelete(newAttrsUnEsc, \"heading-fold\")\n\t\t\tbreak\n\t\t}\n\t}\n\n\tfor name, value := range nameValues {\n\t\tvalue = util.RemoveInvalidRetainCtrl(value)\n\t\tvalue = strings.TrimSpace(value)\n\t\tlowerName := strings.ToLower(name)\n\t\t// 转换为小写再验证属性名\n\t\tif !isValidAttrName(lowerName) {\n\t\t\terr = errors.New(Conf.Language(25) + \" [\" + node.ID + \"]\")\n\t\t\treturn\n\t\t}\n\t\tif lowerName == \"data-task\" {\n\t\t\terr = errors.New(`setting or removing [data-task] attribute is not allowed via this interface. Please use \"/api/block/updateTaskListItemMarker\" or \"/api/block/batchUpdateTaskListItemMarker\" to update the task list item marker`)\n\t\t\treturn\n\t\t}\n\t\tif DocSortModeAttr == lowerName {\n\t\t\tif ast.NodeDocument != node.Type || IsBoxDoc(boxID, node.ID) {\n\t\t\t\terr = fmt.Errorf(\"attribute [%s] is only supported on regular document roots\", DocSortModeAttr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif \"\" != value {\n\t\t\t\tsortMode, parseErr := strconv.Atoi(value)\n\t\t\t\tif nil != parseErr || !IsValidDocSortMode(sortMode) {\n\t\t\t\t\terr = fmt.Errorf(\"invalid document sort mode [%s]\", value)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tvalue = strconv.Itoa(sortMode)","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/blockial.go#L372-L408","documentation":"setNodeAttrs0 validates each attribute name (lower-cased) with isValidAttrName; a name that is not lowercase letters/digits/hyphens and not starting with a lowercase letter produces Conf.Language(25): 'The attribute name can only contain lowercase English letters, digits, and hyphens, and must start with a lowercase English letter', suffixed with ' [' + node.ID + ']'. This enforces the IAL attribute-name grammar of the Kramdown storage format.","triggerScenarios":"POST /api/attr/setBlockAttrs or batchSetBlockAttrs (and internal setNodeAttrs* callers like updateBoundBlockAvsAttribute) with an attribute key containing uppercase letters, spaces, underscores, Chinese characters, or starting with a digit/hyphen.","commonSituations":"Plugins generating attr names from user input or CamelCase identifiers (e.g. 'myAttr', 'my_attr'); converting external data keys directly into SiYuan attrs; typos like 'Title'.","solutions":["Normalize the attribute name: lowercase it, replace underscores/spaces with hyphens, strip illegal characters","Prefix custom attributes with 'custom-' (convention for user-defined keys) and keep the rest [a-z0-9-]","Reject or rename invalid keys in the caller before sending the request","Map external metadata (e.g. YAML front matter keys) through a sanitizer function"],"exampleFix":"// before\nawait fetchPost('/api/attr/setBlockAttrs', {id, attrs: {'myAttr': '1'}});\n// after\nconst safe = k => 'custom-' + k.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+/, '');\nawait fetchPost('/api/attr/setBlockAttrs', {id, attrs: {[safe('myAttr')]: '1'}});","handlingStrategy":"validation","validationCode":"function isValidAttrName(name) { return /^[a-z][a-z0-9-]*$/.test(name); }","typeGuard":"null","tryCatchPattern":"try { await setBlockAttrs(id, attrs); } catch (e) { if (/attribute name/i.test(String(e))) sanitizeAndRetry(); else throw e; }","preventionTips":["Sanitize external keys to [a-z][a-z0-9-]* before sending","Use the 'custom-' prefix convention for user-defined attributes","Lowercase and hyphenate CamelCase/snake_case identifiers","Reject invalid names in UI inputs at entry time"],"tags":["siyuan","attribute-name","validation","ial"],"backgroundTag":"invalid-argument-value","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}