siyuan-note/siyuan · error

load block tree [%s] failed: tree is empty

Error message

load block tree [%s] failed: tree is empty

What it means

Returned by buildBlockUpdateOperations when loadTree returned (nil, nil) or a tree with a nil Root - the loader reported success but the tree is empty. This indicates a structurally invalid or empty .sy file that the loader could not reject cleanly.

Source

Thrown at kernel/model/block_update.go:116

			return nil, nil, parseErr
		}

		var oldTree *parse.Tree
		var cacheKey blockUpdateTreeKey
		hasCacheKey := false
		if blockTree := resolveTree(input.ID); nil != blockTree {
			cacheKey = blockUpdateTreeKey{boxID: blockTree.BoxID, rootID: blockTree.RootID}
			hasCacheKey = true
			oldTree = treeCache[cacheKey]
		}
		if nil == oldTree {
			var loadErr error
			oldTree, loadErr = loadTree(input.ID)
			if loadErr != nil {
				return nil, nil, fmt.Errorf("load block tree [%s] failed: %w", input.ID, loadErr)
			}
			if nil == oldTree || nil == oldTree.Root {
				return nil, nil, fmt.Errorf("load block tree [%s] failed: tree is empty", input.ID)
			}
			treeCache[blockUpdateTreeKey{boxID: oldTree.Box, rootID: oldTree.ID}] = oldTree
			if hasCacheKey {
				treeCache[cacheKey] = oldTree
			}
		}
		oldNode := treenode.GetNodeInTree(oldTree, input.ID)
		if nil == oldNode {
			return nil, nil, fmt.Errorf("block [%s] not found", input.ID)
		}

		if _, ok := rootIDSet[oldTree.ID]; !ok {
			rootIDSet[oldTree.ID] = struct{}{}
			rootIDs = append(rootIDs, oldTree.ID)
		}

		if ast.NodeDocument == oldNode.Type {
			if validateErr := treenode.ValidateBlockSubtree(dataTree.Root); validateErr != nil {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Open the .sy file and confirm it has a complete document tree (non-empty Root).
  2. Restore the document from history (Settings - Data history).
  3. If reproducible, report a loader bug - the loader should return an error rather than an empty tree.
  4. Rebuild the index after the file is restored.
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(syPath)
if err == nil && fi.Size() == 0 {
    return fmt.Errorf("sy file %s is empty", syPath)
}

Try / catch

ops, roots, err := buildBlockUpdateOperations(inputs, resolver, loader)
if err != nil && strings.Contains(err.Error(), "tree is empty") {
    // restore from history, rebuild index, then retry
}

Prevention

When it happens

Trigger: Zero-byte or whitespace-only .sy file; .sy file containing JSON but missing the root node; loader bug that returns an empty tree on parse failure.

Common situations: Truncated file from an interrupted write/sync; corrupted snapshot applied; manual edit that emptied the document body.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/49789f7704eae302. Report an issue: GitHub.