siyuan-note/siyuan · error

block is not a task list item

Error message

block is not a task list item

What it means

Thrown by buildUpdatedTaskListItemBlockDOM (kernel/api/block_op.go) when the node is a list item but li.ListData.Typ != 3. In Lute's AST, Typ 3 identifies task list items; Typ 1 (bullet) and Typ 2 (ordered) are plain list items with no checkbox marker, so there is nothing for the task-marker API to update.

Source

Thrown at kernel/api/block_op.go:70

		return "", errors.New("get block failed: " + err.Error())
	}

	if "NodeListItem" != block.Type {
		return "", errors.New("block is not a list item")
	}

	tree, err := filesys.LoadTree(block.Box, block.Path, luteEngine)
	if err != nil {
		return "", errors.New("load tree failed: " + err.Error())
	}

	li := treenode.GetNodeInTree(tree, id)
	if li == nil {
		return "", errors.New("block not found")
	}

	if 3 != li.ListData.Typ {
		return "", errors.New("block is not a task list item")
	}

	if 1 != len(marker) {
		return "", errors.New("task list item marker length should be 1")
	}

	liMarker := marker[0]
	if '[' == liMarker || ']' == liMarker {
		return "", errors.New("task list item marker can not be [ or ]")
	}

	markerNode := li.ChildByType(ast.NodeTaskListItemMarker)
	if nil == markerNode {
		return "", errors.New("task list item marker not found")
	}

	markerNode.TaskListItemMarker = liMarker
	markerNode.TaskListItemChecked = ' ' != markerNode.TaskListItemMarker

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Check ListData type via getBlockKramdown (task items render with [ ] / [x] markers) before calling
  2. Convert the list to a task list in the editor (retype the marker as [ ]), then call the API
  3. Filter to task items only in batch operations
  4. Use the correct API for plain list items (e.g. list marker/type change via transactions) instead of the task-marker endpoint

Example fix

// before
// id belongs to '- plain bullet item'
fetchPost('/api/block/updateTaskListItemMarker', { id, marker: 'x' }); // "block is not a task list item"

// after
const kd = await fetchPost('/api/block/getBlockKramdown', { id });
if (/\[([ xX])\]/.test(kd.data.kramdown)) {
  fetchPost('/api/block/updateTaskListItemMarker', { id, marker: 'x' });
}
Defensive patterns

Strategy: type-guard

Validate before calling

const kd = await fetchPost('/api/block/getBlockKramdown', { id });
const isTask = /\[[ xX]?\]/.test(kd.data?.kramdown ?? '') || kd.data?.type === 'NodeListItem' && hasTaskMarker(kd.data);
if (!isTask) throw new Error('not a task list item');
await fetchPost('/api/block/updateTaskListItemMarker', { id, marker });

Type guard

function isTaskListItem(kramdown: string): boolean {
  return /^\s*(?:[-*+\d.)]+)\s+\[( |x|X)\]/.test(kramdown);
}

Try / catch

if (e.message === 'block is not a task list item') { /* convert the list to a task list first, or skip */ }

Prevention

When it happens

Trigger: Passing the id of a bullet-list or ordered-list item to /api/block/updateTaskListItemMarker; the document was converted from a task list to a plain list after the id was captured; batch marker updates applied to mixed lists.

Common situations: A plugin iterates list items and assumes every NodeListItem is a task item; user toggled the list style between -/* and [ ] syntax; imported Markdown where plain lists outnumber task lists.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/68fd965df3880661. Report an issue: GitHub.