siyuan-note/siyuan · error
setting or removing [data-task] attribute is not allowed…
Error message
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
What it means
setNodeAttrs0 explicitly forbids writing the 'data-task' attribute through the generic attribute APIs, returning a fixed error directing callers to the dedicated task-marker endpoints. data-task is derived from task-list item markers, so direct mutation would desynchronize the attribute from the actual markdown checkbox state.
Solutions
- Call /api/block/updateTaskListItemMarker or /api/block/batchUpdateTaskListItemMarker instead to change task state
- Skip/delete 'data-task' keys from batch payloads and handle them via the marker endpoint separately
- If you just want to read task state, keep using the attribute but never write it through setBlockAttrs
Example fix
// before
await fetchPost('/api/attr/setBlockAttrs', {id, attrs: {'data-task': 'done'}});
// after
await fetchPost('/api/block/updateTaskListItemMarker', {id: blockId, type: 't', data: 'x'}); Defensive patterns
Strategy: validation
Validate before calling
if ('data-task' in attrs || Object.keys(attrs).some(k => k.toLowerCase() === 'data-task')) {
// route to /api/block/updateTaskListItemMarker instead
} Type guard
null
Try / catch
try { await setBlockAttrs(id, attrs); } catch (e) { if (String(e).includes('data-task')) { await updateTaskListItemMarker(id, 'x'); delete attrs['data-task']; await setBlockAttrs(id, attrs); } else throw e; } Prevention
- Never write data-task directly; always use the task-marker endpoints
- Strip data-task from generic attr payloads before sending
- Update task state via block marker updates so the attribute stays consistent
- Check for the key case-insensitively (validation is case-insensitive)
When it happens
Trigger: POST /api/attr/setBlockAttrs or /api/attr/batchSetBlockAttrs (or any caller routing into setNodeAttrs0) with a key of 'data-task' (case-insensitive), on a task-list item block.
Common situations: Scripts trying to toggle todo state by editing data-task directly (e.g. moving items to 'done'); plugins syncing external task systems into SiYuan; automation migrating from older versions where direct attr writes worked.
Related errors
- block is not a task list item
- block not found
- task list item marker can not be [ or ]
- task list item marker length should be 1
- task list item marker not found
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/d854e9d75e20021d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/blockial.go:394
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)
}
}
// 处理文档标签 https://github.com/siyuan-note/siyuan/issues/13311View on GitHub (pinned to 9f775e8a12)