siyuan-note/siyuan · error
notebook not found
Error message
notebook not found
What it means
Sentinel error model.ErrBoxNotFound (kernel/model/tree.go:202). It means the notebook (box) ID is not among the configured notebooks - Conf.GetBox(boxID) returned nil (kernel/model/mount.go:57). It is returned by many file/document operations (file.go, transaction.go, box_doc.go, attribute_view_new_item.go) whenever a boxID parameter cannot be resolved.
Solutions
- List current notebooks via /api/notebook/lsNotebooks and use one of the returned ids
- If the notebook should exist, check you are in the right workspace and reopen or recreate the notebook
- Match with errors.Is(err, model.ErrBoxNotFound) and refresh cached IDs instead of retrying blindly
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the notebook exists in this workspace:
// GET /api/notebook/lsNotebooks -> notebooks[].id
// In Go: if nil == Conf.GetBox(boxID) { /* refresh ids, abort */ } Type guard
func isBoxNotFound(err error) bool {
return errors.Is(err, model.ErrBoxNotFound)
} Try / catch
if err := someFileOp(boxID, ...); err != nil {
if errors.Is(err, model.ErrBoxNotFound) {
// notebook id is stale: re-list notebooks and refresh cached ids
} else {
// propagate
}
} Prevention
- Never cache notebook IDs across workspace switches or notebook recreation
- Re-resolve box IDs from /api/notebook/lsNotebooks at the start of each batch job
- Treat ErrBoxNotFound as a cache-invalidation signal, not a transient retry candidate
When it happens
Trigger: API calls carrying a boxID that no longer exists in conf: the notebook was deleted or recreated with a new ID, the ID comes from a different workspace, or it is simply mistyped. Examples: /api/filetree/* ops with a stale box id, transactions targeting an unresolvable box (transaction.go:2417).
Common situations: Plugins caching box IDs across workspace switches or after notebook recreation; scripts exported from another machine; nightly jobs running against the wrong workspace.
Related errors
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/d446a4e189ad465d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/tree.go:202
}
// 从绝对路径推导 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 afa823b6b4)