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

  1. 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
  2. Inspect the .sy file JSON for the block and confirm whether TaskListItemMarker exists; fix or recreate the list item if it is missing
  3. Restore the document from SiYuan history (Data history / snapshot) if the block was corrupted by sync or an external edit
  4. 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

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


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)