siyuan-note/siyuan · error
task list item marker not found
Error message
task list item marker not found
What it means
Returned when the loaded list-item node has no child of type ast.NodeTaskListItemMarker. The kernel treats ListData.Typ==3 as a task list item, but the actual checkbox marker sub-node (the `[x]`/`[ ]` glyph holder) is missing from the tree — usually indicating data corruption or a hand-edited/malformed .sy file rather than an API misuse.
Source
Thrown at kernel/api/block_op.go:84
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
treenode.RefreshUpdated(li)
return luteEngine.RenderNodeBlockDOM(li), nil
}
func updateTaskListItemMarker(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok {
return
}View on GitHub (pinned to 251596fc0d)
Solutions
- Inspect the block's .sy file / use /api/block/getBlockKramdown to confirm the node structure is intact.
- If the block is malformed, recreate the task list item in the editor so the kernel regenerates the marker child node.
- In programmatic node construction, always append a NodeTaskListItemMarker child when setting ListData.Typ=3 (mirror the test pattern).
- Guard callers to skip blocks where ChildByType(NodeTaskListItemMarker) is nil instead of treating them as toggleable.
Defensive patterns
Strategy: type-guard
Validate before calling
// Fetch block kramdown and check it contains a task marker before toggling
const kd = await getBlockKramdown(id);
if (!/\[[ xX]\]/.test(kd)) { throw new Error('block has no task marker child; recreate it'); } Type guard
// Structural guard: only treat as toggleable when a marker child exists
function isToggleableTaskItem(node): node is TaskItem {
return node?.ListData?.Typ === 3 && node.children?.some(c => c.Type === 'NodeTaskListItemMarker');
} Try / catch
try { await updateTaskMarker(id, marker); }
catch (e) { if (/marker not found/.test(e.msg)) { /* recreate block via editor, skip */ } else throw e; } Prevention
- When building task items programmatically, always append a NodeTaskListItemMarker child (see transaction_list_item_fold_test.go).
- Periodically validate notebook tree integrity for encrypted/imported data.
- Skip blocks whose tree lacks the marker rather than assuming toggle works.
When it happens
Trigger: POST /api/block/updateTaskListItemMarker on a node whose ListData.Typ==3 passed the earlier guard but whose children do not include a NodeTaskListItemMarker. This arises with manually constructed/edited trees, partially migrated blocks, or blocks produced by older versions that did not always emit the marker child.
Common situations: Notebooks imported from Markdown where the importer set Typ=3 but did not synthesize the marker child. Direct .sy file editing or external sync tools that stripped child nodes. Bugs in custom block-generation code that sets ListData.Typ=3 without appending a NodeTaskListItemMarker child (see transaction_list_item_fold_test.go:19 for the correct construction pattern).
Related errors
- task list item marker length should be 1
- task list item marker can not be [ or ]
- setting or removing [data-task] attribute is not allowed via
- local storage value for key [%s] must not be empty
- encrypted notebook is locked, please unlock it first
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/84fc50895405b91c.
Report an issue: GitHub.