siyuan-note/siyuan · error · ErrBoxClosed
notebook closed
Error message
notebook closed
What it means
Sentinel error ErrBoxClosed declared at tree.go:203 ('notebook closed'). Returned when an operation requires an open notebook but the notebook is in a closed state. Throw sites include mount.go (notebook closed during mount) and import/file operations. notebooks must be opened before their trees can be read/written (encryption keys, indexing).
Source
Thrown at kernel/model/tree.go:203
// 从绝对路径推导 box 内相对路径作为 AAD
relPath := filepath.ToSlash(strings.TrimPrefix(localPath, filepath.Join(util.DataDir, boxID)+string(os.PathSeparator)))
if data, err = DecryptFile(boxID, relPath, dek, data); err != nil {
logging.LogErrorf("decrypt tree [path=%s] failed: %s", localPath, 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 251596fc0d)
Solutions
- Open the notebook first (UI notebook open action, or the corresponding API) before retrying the operation.
- Check Conf.GetOpenedBoxes()/Conf.Box(id) and prompt the user to open the closed notebook.
- Use errors.Is(err, model.ErrBoxClosed) to surface a 'please open notebook X' message instead of a generic error.
Example fix
// before — operate on possibly-closed notebook
err := ImportData(boxID, ...)
// may return ErrBoxClosed
// after — ensure notebook is open
if Conf.Box(boxID) == nil {
// prompt user to open notebook, then retry
} Defensive patterns
Strategy: validation
Validate before calling
func boxIsOpen(boxID string) bool {
for _, b := range model.Conf.GetOpenedBoxes() {
if b.ID == boxID { return true }
}
return false
} Try / catch
err := someBoxOp(boxID)
if errors.Is(err, model.ErrBoxClosed) {
promptUserToOpenNotebook(boxID)
} Prevention
- Check the notebook is in GetOpenedBoxes() before write operations.
- For encrypted notebooks, ensure the user has unlocked/opened them.
- Distinguish ErrBoxClosed (openable) from ErrBoxNotFound (gone).
When it happens
Trigger: Calling a write/read operation on a notebook that the user has closed (closed notebooks are listed in Conf.GetClosedBoxes()); importing into a closed notebook; opening a doc whose notebook was closed after the session started. mount.go returns it when the box is found in closed boxes rather than open ones.
Common situations: An encrypted notebook that the user closed (locked) — its blocktree data is in the encrypted DB and inaccessible until reopened; a notebook manually closed via the UI; an operation triggered by a plugin that does not check notebook state.
Related errors
- notebook unindexed
- notebook not found
- encrypted notebook is locked, please unlock it first
- encrypted notebook is locked, please unlock it first
- path belongs to encrypted notebook [%s]: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/747f91c4c1683d02.
Report an issue: GitHub.