siyuan-note/siyuan · error
Conf.Language(25) + " [" + node.ID + "]"
Error message
Conf.Language(25) + " [" + node.ID + "]"
What it means
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.
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
Example fix
// before
await fetchPost('/api/attr/setBlockAttrs', {id, attrs: {'myAttr': '1'}});
// after
const safe = k => 'custom-' + k.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+/, '');
await fetchPost('/api/attr/setBlockAttrs', {id, attrs: {[safe('myAttr')]: '1'}}); Defensive patterns
Strategy: validation
Validate before calling
function isValidAttrName(name) { return /^[a-z][a-z0-9-]*$/.test(name); } Type guard
null
Try / catch
try { await setBlockAttrs(id, attrs); } catch (e) { if (/attribute name/i.test(String(e))) sanitizeAndRetry(); else throw e; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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'.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Conf.Language(25) + " [" + node.ID + "]" (localized invalid…
- 106
- 199
- block operation context
- Cannot create a file starting with .
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/a7fa1e47397ed381.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/blockial.go:390
}
}
}
oldAttrs = parse.IAL2Map(node.KramdownIAL)
newAttrsUnEsc := parse.IAL2MapUnEsc(node.KramdownIAL)
for name := range nameValues {
if "fold" == strings.ToLower(name) {
delete(newAttrsUnEsc, "heading-fold")
break
}
}
for name, value := range nameValues {
value = util.RemoveInvalidRetainCtrl(value)
value = strings.TrimSpace(value)
lowerName := strings.ToLower(name)
// 转换为小写再验证属性名
if !isValidAttrName(lowerName) {
err = errors.New(Conf.Language(25) + " [" + node.ID + "]")
return
}
if lowerName == "data-task" {
err = 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`)
return
}
if DocSortModeAttr == lowerName {
if ast.NodeDocument != node.Type || IsBoxDoc(boxID, node.ID) {
err = fmt.Errorf("attribute [%s] is only supported on regular document roots", DocSortModeAttr)
return
}
if "" != value {
sortMode, parseErr := strconv.Atoi(value)
if nil != parseErr || !IsValidDocSortMode(sortMode) {
err = fmt.Errorf("invalid document sort mode [%s]", value)
return
}
value = strconv.Itoa(sortMode)View on GitHub (pinned to 9f775e8a12)