{"record":{"id":"275c49555050728d","repo":"siyuan-note/siyuan","slug":"tree-not-found","errorCode":null,"errorMessage":"tree not found","messagePattern":"tree not found","errorType":"error_code","errorClass":"ErrTreeNotFound","httpStatus":null,"severity":"error","filePath":"kernel/model/tree.go","lineNumber":205,"sourceCode":"\t\tif data, err = DecryptFile(boxID, relPath, dek, data); err != nil {\n\t\t\tlogging.LogErrorf(\"decrypt tree [path=%s] failed: %s\", localPath, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tret, err = dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)\n\tif err != nil {\n\t\tlogging.LogErrorf(\"parse json to tree [%s] failed: %s\", localPath, err)\n\t\treturn\n\t}\n\treturn\n}\n\nvar (\n\tErrBoxNotFound   = errors.New(\"notebook not found\")\n\tErrBoxClosed     = errors.New(\"notebook closed\")\n\tErrBlockNotFound = errors.New(\"block not found\")\n\tErrTreeNotFound  = errors.New(\"tree not found\")\n\tErrIndexing      = errors.New(\"indexing\")\n\tErrBoxUnindexed  = errors.New(\"notebook unindexed\")\n\tErrInvalidID     = errors.New(\"invalid id\")\n)\n\nfunc LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {\n\treturn LoadTreeByBlockIDWithReindexInBox(id, \"\")\n}\n\n// LoadTreeByBlockIDWithReindexInBox 与 LoadTreeByBlockIDWithReindex 一致，但按 boxID 路由 blocktree 查询。\nfunc LoadTreeByBlockIDWithReindexInBox(id, boxID string) (ret *parse.Tree, err error) {\n\tif \"\" == id {\n\t\tlogging.LogWarnf(\"block id is empty\")\n\t\treturn nil, ErrTreeNotFound\n\t}\n\n\tbt := treenode.GetBlockTreeInBox(id, boxID)\n\tif nil == bt && \"\" == boxID {","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/tree.go#L187-L223","documentation":"Sentinel error ErrTreeNotFound declared at tree.go:205 ('tree not found'). Returned when a document/tree cannot be located — distinct from ErrBlockNotFound in that it concerns the document (root tree) rather than an individual block. Throw sites include tree.go (LoadTreeByBlockID variants when blocktree entry is absent even after filesystem reindex attempt), history_diff.go, block.go:561, and indexTreeInFilesystem when the tree is absent on disk.","triggerScenarios":"Loading a document whose root block ID has no blocktree entry and is not found on the filesystem either (indexTreeInFilesystem returns it after findUnindexedTreePathInAllBoxes yields nothing); an invalid/non-node-ID-pattern id passed to loadTreeByBlockIDInBox0 (ast.IsNodeIDPattern fails); a document was deleted from disk but referenced.","commonSituations":"Document deleted but a bookmark/history/external link still references it; an ID that is not a valid 20-char node ID pattern; the .sy file was removed manually from the data dir; cross-workspace doc reference where the doc does not exist.","solutions":["Validate the ID matches ast.IsNodeIDPattern before loading.","If a legitimately deleted doc, surface 'document removed' and clean up dangling references.","If the .sy file should exist, verify it is on disk under <data>/<box>/ and reindex the notebook.","Use errors.Is(err, model.ErrTreeNotFound) to distinguish from ErrIndexing (retry) vs genuine not-found."],"exampleFix":"// before — pass unvalidated id\ntree, err := LoadTreeByBlockID(maybeBadID)\n\n// after — validate pattern first\nif !ast.IsNodeIDPattern(id) {\n    return nil, ErrTreeNotFound\n}","handlingStrategy":"type-guard","validationCode":"import \"github.com/siyuan-note/siyuan/kernel/treenode/.../ast\"\n\nfunc isValidDocID(id string) bool {\n    return ast.IsNodeIDPattern(id)\n}","typeGuard":"func isLoadableDocID(id string) bool {\n    if !ast.IsNodeIDPattern(id) { return false }\n    return treenode.GetBlockTree(id) != nil\n}","tryCatchPattern":"tree, err := model.LoadTreeByBlockID(id)\nif errors.Is(err, model.ErrTreeNotFound) {\n    if !ast.IsNodeIDPattern(id) {\n        return fmt.Errorf(\"invalid doc id format\")\n    }\n    return fmt.Errorf(\"document not found\")\n}","preventionTips":["Validate ID format with ast.IsNodeIDPattern before loading.","Clean up bookmarks/refs to deleted docs.","Reindex the notebook if a doc that should exist returns ErrTreeNotFound."],"tags":["tree","document","sentinel","not-found","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}