{"record":{"id":"49789f7704eae302","repo":"siyuan-note/siyuan","slug":"load-block-tree-s-failed-tree-is-empty","errorCode":null,"errorMessage":"load block tree [%s] failed: tree is empty","messagePattern":"load block tree \\[(.+?)\\] failed: tree is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/block_update.go","lineNumber":116,"sourceCode":"\t\t\treturn nil, nil, parseErr\n\t\t}\n\n\t\tvar oldTree *parse.Tree\n\t\tvar cacheKey blockUpdateTreeKey\n\t\thasCacheKey := false\n\t\tif blockTree := resolveTree(input.ID); nil != blockTree {\n\t\t\tcacheKey = blockUpdateTreeKey{boxID: blockTree.BoxID, rootID: blockTree.RootID}\n\t\t\thasCacheKey = true\n\t\t\toldTree = treeCache[cacheKey]\n\t\t}\n\t\tif nil == oldTree {\n\t\t\tvar loadErr error\n\t\t\toldTree, loadErr = loadTree(input.ID)\n\t\t\tif loadErr != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"load block tree [%s] failed: %w\", input.ID, loadErr)\n\t\t\t}\n\t\t\tif nil == oldTree || nil == oldTree.Root {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"load block tree [%s] failed: tree is empty\", input.ID)\n\t\t\t}\n\t\t\ttreeCache[blockUpdateTreeKey{boxID: oldTree.Box, rootID: oldTree.ID}] = oldTree\n\t\t\tif hasCacheKey {\n\t\t\t\ttreeCache[cacheKey] = oldTree\n\t\t\t}\n\t\t}\n\t\toldNode := treenode.GetNodeInTree(oldTree, input.ID)\n\t\tif nil == oldNode {\n\t\t\treturn nil, nil, fmt.Errorf(\"block [%s] not found\", input.ID)\n\t\t}\n\n\t\tif _, ok := rootIDSet[oldTree.ID]; !ok {\n\t\t\trootIDSet[oldTree.ID] = struct{}{}\n\t\t\trootIDs = append(rootIDs, oldTree.ID)\n\t\t}\n\n\t\tif ast.NodeDocument == oldNode.Type {\n\t\t\tif validateErr := treenode.ValidateBlockSubtree(dataTree.Root); validateErr != nil {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/block_update.go#L98-L134","documentation":"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.","triggerScenarios":"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.","commonSituations":"Truncated file from an interrupted write/sync; corrupted snapshot applied; manual edit that emptied the document body.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fi, err := os.Stat(syPath)\nif err == nil && fi.Size() == 0 {\n    return fmt.Errorf(\"sy file %s is empty\", syPath)\n}","typeGuard":null,"tryCatchPattern":"ops, roots, err := buildBlockUpdateOperations(inputs, resolver, loader)\nif err != nil && strings.Contains(err.Error(), \"tree is empty\") {\n    // restore from history, rebuild index, then retry\n}","preventionTips":["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."],"tags":["block-update","corruption","load-tree"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}