siyuan-note/siyuan · error

load tree failed: %s

Error message

load tree failed: %s

What it means

Third failure mode of buildUpdatedTaskListItemBlockDOM (kernel/api/block_op.go): the block was found in the index and is a list item, but filesys.LoadTree failed to load the .sy document file for block.Box/block.Path. The underlying filesystem error is appended to the prefix, so the message tells you whether it was a missing file, permission problem, or parse failure.

Source

Thrown at kernel/api/block_op.go:61

	if util.InvalidIDPattern(input.ID, ret) {
		return input, false
	}
	return input, true
}

func buildUpdatedTaskListItemBlockDOM(id, marker string, luteEngine *lute.Lute) (data string, err error) {
	block, err := model.GetBlock(id, nil)
	if err != nil {
		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 ]")

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Check the notebook is mounted and the .sy file exists on disk at the path reported in the block info
  2. Remount/reopen the notebook and retry the update
  3. If the file is missing but content matters, recover from history (.siyuan/history or /api/history/) or the data repo
  4. Rebuild the index so stale entries pointing at gone files are cleaned up; inspect the appended underlying error in the kernel log
Defensive patterns

Strategy: validation

Validate before calling

const info = await fetchPost('/api/block/getBlockInfo', { id });
const nb = await fetchGet('/api/notebook/lsNotebooks');
const mounted = nb.data.notebooks.some(n => n.id === info.data.box && !n.closed);
if (!mounted) throw new Error('notebook not mounted; open it before updating');
await fetchPost('/api/block/updateTaskListItemMarker', { id, marker });

Type guard

const isMountedNotebook = (boxId: string, notebooks: { id: string; closed: boolean }[]): boolean =>
  notebooks.some(n => n.id === boxId && !n.closed);

Try / catch

if (/^load tree failed:/.test(e.message)) {
  // underlying fs error: check .sy exists on disk, remount notebook, or reindex; retry after fix
}

Prevention

When it happens

Trigger: The .sy file was deleted, moved, or renamed on disk while its index entry survived (unmounted notebook, external file manipulation, interrupted sync); the notebook containing the block is closed/unmounted between index read and tree load; the .sy file is corrupted and cannot be parsed; filesystem permission or disk errors.

Common situations: Sync tool rewrote the notebook directory mid-call; user closed the notebook in another window; .sy files edited by external scripts or merged badly; antivirus/locking software blocking reads on Windows.

Related errors


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