siyuan-note/siyuan · error
ErrBoxClosed
ErrBoxClosed
Error message
notebook closed
What it means
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.
Source
Thrown at kernel/model/tree.go:211
logging.LogErrorf("decrypt tree [path=%s] failed: %s", localPath, err)
return
}
}
if err = treenode.CheckSpecJSON(data); nil != err {
return
}
ret, err = dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)
if err != nil {
logging.LogErrorf("parse json to tree [%s] failed: %s", localPath, err)
return
}
return
}
var (
ErrBoxNotFound = errors.New("notebook not found")
ErrBoxClosed = errors.New("notebook closed")
ErrBlockNotFound = errors.New("block not found")
ErrTreeNotFound = errors.New("tree not found")
ErrIndexing = errors.New("indexing")
ErrBoxUnindexed = errors.New("notebook unindexed")
ErrInvalidID = errors.New("invalid id")
)
func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {
return LoadTreeByBlockIDWithReindexInBox(id, "")
}
// LoadTreeByBlockIDWithReindexInBox 与 LoadTreeByBlockIDWithReindex 一致,但按 boxID 路由 blocktree 查询。
func LoadTreeByBlockIDWithReindexInBox(id, boxID string) (ret *parse.Tree, err error) {
if "" == id {
logging.LogWarnf("block id is empty")
return nil, ErrTreeNotFound
}
View on GitHub (pinned to 8641553a1f)
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
Example fix
// before
if err := writeDoc(boxID, path, title); err != nil { return err }
// after
if err := writeDoc(boxID, path, title); err != nil {
if errors.Is(err, model.ErrBoxClosed) {
return fmt.Errorf("notebook [%s] is closed; run `notebook open --id %s` first", boxID, boxID)
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
if isNotebookClosed(boxID) {
return fmt.Errorf("notebook %s is closed; open it first", boxID)
} Try / catch
if errors.Is(err, model.ErrBoxClosed) {
return fmt.Errorf("notebook [%s] is closed; run `notebook open --id %s` first", boxID, boxID)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Please unlock the encrypted notebook first
- notebook closed
- initialize encrypted notebook document failed: %w
- can not get or create rollback box
- Conf.Language(314)
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/4ea9007d856a5517.
Report an issue: GitHub.