{"record":{"id":"4ea9007d856a5517","repo":"siyuan-note/siyuan","slug":"errboxclosed","errorCode":"ErrBoxClosed","errorMessage":"notebook closed","messagePattern":"notebook closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/tree.go","lineNumber":211,"sourceCode":"\t\t\tlogging.LogErrorf(\"decrypt tree [path=%s] failed: %s\", localPath, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tif err = treenode.CheckSpecJSON(data); nil != err {\n\t\treturn\n\t}\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","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/tree.go#L193-L229","documentation":"ErrBoxClosed is the sentinel error for a notebook that exists but is currently closed (not loaded) in the workspace. Operations that write to or read from a closed notebook return it so callers can prompt the user (or CLI) to open the notebook first.","triggerScenarios":"Writing a document or creating a daily note in a notebook whose state is 'closed'; CLI commands hitting a closed box, intercepted by formatNotebookWriteError which appends 'run `notebook open --id <id>`'; getOpenedBox failing to find the box among open notebooks.","commonSituations":"User closed a notebook in the UI but an automation/plugin/CLI still targets it; headless/CLI usage against a workspace where the notebook defaults to closed; daily-note job running while its notebook is closed.","solutions":["Open the notebook first (UI right-click - Open, or CLI `notebook open --id <boxID>`) and retry the operation","Check notebook state via /api/notebook/lsNotebooks and only operate on notebooks with closed == false","In CLI/scripts, call the notebook open command before any doc write when the box reports closed"],"exampleFix":"// before\nif err := writeDoc(boxID, path, title); err != nil { return err }\n// after\nif err := writeDoc(boxID, path, title); err != nil {\n    if errors.Is(err, model.ErrBoxClosed) {\n        return fmt.Errorf(\"notebook [%s] is closed; run `notebook open --id %s` first\", boxID, boxID)\n    }\n    return err\n}","handlingStrategy":"validation","validationCode":"if isNotebookClosed(boxID) {\n    return fmt.Errorf(\"notebook %s is closed; open it first\", boxID)\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, model.ErrBoxClosed) {\n    return fmt.Errorf(\"notebook [%s] is closed; run `notebook open --id %s` first\", boxID, boxID)\n}","preventionTips":["Check notebook state (closed == false) before scripted writes","Open notebooks programmatically before automation jobs","Avoid writing to notebooks not visible in the current workspace UI"],"tags":["go","notebook","closed-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}