siyuan-note/siyuan · error
ErrBoxNotFound
ErrBoxNotFound
Error message
notebook not found
What it means
ErrBoxNotFound is the sentinel error in kernel/model/tree.go's error var block meaning the notebook (box) ID does not exist in the workspace. Domain functions return it (often via errors wrapping) so API handlers can detect a missing notebook and respond distinctly, e.g. with {unavailableNotebook: true}.
Source
Thrown at kernel/model/tree.go:210
if data, err = DecryptFile(boxID, relPath, dek, data); err != nil {
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
- List current notebooks (/api/notebook/lsNotebooks) and confirm the box ID exists; update the client's references to a valid notebook
- Reopen the workspace or rescan notebooks so the registry is refreshed if the notebook exists on disk but is not loaded
- Remove or correct the stale daily-note configuration under Settings - Daily Note if it points to a deleted notebook
- Handle errors.Is(err, model.ErrBoxNotFound) in the caller and surface 'unavailableNotebook' instead of a raw error
Example fix
// before
result, err := model.CreateAttributeViewItemDocs(avID, blockID, saveMode, itemIDs)
// after
if errors.Is(err, model.ErrBoxNotFound) {
ret.Code = 1
ret.Data = map[string]any{"unavailableNotebook": true}
return
} Defensive patterns
Strategy: validation
Validate before calling
boxes, _ := listNotebooks()
exists := false
for _, b := range boxes {
if b.ID == boxID && !b.Closed { exists = true }
}
if !exists { return fmt.Errorf("notebook %s does not exist", boxID) } Try / catch
if errors.Is(err, model.ErrBoxNotFound) {
ret.Data = map[string]any{"unavailableNotebook": true}
return
} Prevention
- Refresh notebook lists after any delete/rename instead of caching box IDs
- Resolve a block's notebook via its ID before writing database items
- Validate daily-note target notebooks in settings
When it happens
Trigger: Calling createAttributeViewItemDocs / setCreateAttributeViewItemResult-backed API (/api/av/* with blockID) or createDailyNote with a block or notebook ID whose containing notebook was deleted or renamed outside the kernel's registry.
Common situations: Client holds a stale notebook ID after the notebook was removed on disk or deleted in another window; daily-note template points at a removed notebook; attribute-view database rows referencing blocks in a deleted notebook.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- view not found
- key not found
- item not found
- Query notebook failed
- Please unlock the encrypted notebook first
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/2563bd4b149693dd.
Report an issue: GitHub.