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
- Open the .sy file and confirm it has a complete document tree (non-empty Root).
- Restore the document from history (Settings - Data history).
- If reproducible, report a loader bug - the loader should return an error rather than an empty tree.
- 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
- Never write partial .sy files; use atomic rename on write.
- Enable document history so empty/corrupt files are recoverable.
- Treat a zero-byte .sy file as a corruption signal before calling update APIs.
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
- load block tree [%s] failed: %w
- parse json [%s] to tree failed: %w
- attribute view [%s] has no block key
- block updates are empty
- invalid block ID [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/49789f7704eae302.
Report an issue: GitHub.