{"record":{"id":"d446a4e189ad465d","repo":"siyuan-note/siyuan","slug":"notebook-not-found","errorCode":null,"errorMessage":"notebook not found","messagePattern":"notebook not found","errorType":"error_code","errorClass":"ErrBoxNotFound","httpStatus":null,"severity":"error","filePath":"kernel/model/tree.go","lineNumber":202,"sourceCode":"\t\t}\n\t\t// 从绝对路径推导 box 内相对路径作为 AAD\n\t\trelPath := filepath.ToSlash(strings.TrimPrefix(localPath, filepath.Join(util.DataDir, boxID)+string(os.PathSeparator)))\n\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}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/tree.go#L184-L220","documentation":"Sentinel error ErrBoxNotFound declared at tree.go:202 ('notebook not found'). Returned by tree/block/transaction operations when the referenced notebook (box) ID does not correspond to any known notebook in the configuration. Callers compare with errors.Is(err, model.ErrBoxNotFound). Throw sites include box_doc.go, block.go, mount.go (Conf.Box returns nil), transaction.go, and the AV new-item path.","triggerScenarios":"An operation targets a boxID that is not registered in conf.json notebooks; the notebook was deleted but a stale reference remains; an API call (filetree, AV) passes a boxID that never existed or was removed. mount.go returns it when Conf.Box(id) is nil.","commonSituations":"A plugin or external API client caches an old boxID after the user deletes the notebook; a sync removed/recreated notebooks leaving dangling references; a typo in the boxID; cross-notebook operation where the target notebook was removed mid-operation.","solutions":["Verify the boxID exists via Conf.GetBoxes()/Conf.Box(id) before issuing the operation.","Refresh the notebook list in the UI/API client to drop stale boxIDs.","If the notebook was deleted intentionally, propagate the 'not found' state to the user rather than retrying.","Use errors.Is(err, model.ErrBoxNotFound) to distinguish from ErrBoxClosed."],"exampleFix":"// before — assumes box exists\nbox := Conf.Box(boxID)\ntree, err := loadTreeByBlockTree(box) // nil deref or ErrBoxNotFound later\n\n// after — guard first\nbox := Conf.Box(boxID)\nif box == nil {\n    return ErrBoxNotFound\n}","handlingStrategy":"validation","validationCode":"func boxExists(boxID string) bool {\n    return model.Conf.Box(boxID) != nil\n}","typeGuard":null,"tryCatchPattern":"tree, err := model.LoadTreeByBlockIDInBox(id, boxID)\nif errors.Is(err, model.ErrBoxNotFound) {\n    return fmt.Errorf(\"notebook %s does not exist\", boxID)\n}","preventionTips":["Validate boxID via Conf.Box(id) before any notebook-scoped operation.","Refresh cached notebook lists after create/delete operations.","Always use errors.Is for sentinel comparison, never string matching."],"tags":["notebook","box","sentinel","not-found","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}