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

  1. Call /api/block/updateTaskListItemMarker or /api/block/batchUpdateTaskListItemMarker instead to change task state
  2. Skip/delete 'data-task' keys from batch payloads and handle them via the marker endpoint separately
  3. 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

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


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/13311

View on GitHub (pinned to 9f775e8a12)