siyuan-note/siyuan · error
task list item marker not found
Error message
task list item marker not found
What it means
After validating the ID and marker, buildUpdatedTaskListItemBlockDOM looks for the list item's ast.NodeTaskListItemMarker child node — the AST node that physically carries the checkbox. If the node has no such child (its ListData.Typ said task item, but no marker node exists in this serialization), the function cannot apply the change and errors out. This signals a structurally inconsistent or corrupted list item in the .sy tree.
Solutions
- Re-render/re-save the affected block in the editor (edit the item, toggle it manually) to let lute normalize the AST, then retry the API call
- Inspect the .sy file JSON for the block and confirm whether TaskListItemMarker exists; fix or recreate the list item if it is missing
- Restore the document from SiYuan history (Data history / snapshot) if the block was corrupted by sync or an external edit
- Rebuild the index; if the on-disk tree itself is malformed, re-export/re-paste the list content into a fresh block
Example fix
// before: blindly updating a possibly-corrupt item
await fetchPost('/api/block/updateTaskListItemMarker', { id, marker: 'x' });
// after: verify the item renders as a task item first, and recreate it if not
const dom = await fetchPost('/api/filetree/getDoc', { id });
if (!dom.content.includes('data-task')) {
await recreateTaskListItem(id); // re-insert the item via insertBlock so lute rebuilds the marker node
}
await fetchPost('/api/block/updateTaskListItemMarker', { id, marker: 'x' }); Defensive patterns
Strategy: try-catch
Try / catch
try {
await fetchPost('/api/block/updateTaskListItemMarker', { id, marker });
} catch (e) {
if (String(e?.msg).includes('task list item marker not found')) {
// AST is inconsistent: recreate the item or restore from history instead of retrying
await recreateBlockFromHistory(id);
} else { throw e; }
} Prevention
- Do not edit .sy files with external tools; only mutate documents through SiYuan
- Keep all clients on the same SiYuan version to avoid AST serialization drift
- After failed syncs, verify affected documents render correctly before scripting against them
- Take snapshots before programmatic bulk edits so blocks can be restored
When it happens
Trigger: Calling the marker update API on a task list item whose stored AST lacks the NodeTaskListItemMarker child — e.g. after a malformed paste/conversion, an external edit of the .sy file, a lute version change in serialization, or document corruption after a failed sync.
Common situations: Documents edited by external tools or older/newer SiYuan versions writing inconsistent ASTs; corrupted .sy content after sync conflicts; a node created programmatically as Typ 3 without the marker child.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- block is not a task list item
- block not found
- block not found or its encrypted notebook is locked
- code block has no code node
- setting or removing [data-task] attribute is not allowed…
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/84fc50895405b91c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/api/block_op.go:69
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
}
var updateTaskListItemMarker = contractHandler(apicontract.UpdateTaskListItemMarker, func(c *gin.Context, request apicontract.TaskListMarkerRequest) apicontract.Response[[]*apicontract.BlockTransaction] {
ret := gulu.Ret.NewResult()
id, marker := request.ID, request.Marker
if util.InvalidIDPattern(id, ret) {
return contractFailure[[]*apicontract.BlockTransaction](ret)
}
View on GitHub (pinned to 9f775e8a12)