siyuan-note/siyuan · error
ErrBoxNotFound
ErrBoxNotFound
Error message
notebook not found
What it means
ErrBoxNotFound is the sentinel error returned when a notebook (box) ID does not exist in the workspace — e.g. lookups of the notebook directory fail. API handlers compare with errors.Is to translate it into client-facing data such as an 'unavailable notebook' payload for attribute-view item creation.
Solutions
- List notebooks (GET /api/notebook/lsNotebooks) and confirm the boxID exists; correct the ID in the caller
- Re-add or reopen the notebook if it was removed from the workspace
- Refresh any cached notebook IDs in your integration before calling CreateAttributeViewItemDocs
- Handle errors.Is(err, model.ErrBoxNotFound) in your client to surface 'unavailable notebook' instead of a raw error
Example fix
// before
value, err := model.CreateAttributeViewItemDocs(avID, blockID, mode, ids)
if err != nil { return err }
// after
if err != nil {
if errors.Is(err, model.ErrBoxNotFound) {
return apicontract.CreateAttributeViewItemDocs.FailureWithData(1, "",
apicontract.NewAVCreateItemDocsResultError(apicontract.AVUnavailableNotebook{UnavailableNotebook: true}))
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// TypeScript: verify notebook exists before the call
const boxes = await fetchPost('/api/notebook/lsNotebooks', {});
if (!boxes.data.notebooks.includes(boxID)) throw new Error('notebook missing: ' + boxID); Type guard
function isBoxNotFound(err: unknown): err is Error {
return err instanceof Error && err.message === 'notebook not found';
} Try / catch
// Go
if errors.Is(err, model.ErrBoxNotFound) {
return apicontract.CreateAttributeViewItemDocs.FailureWithData(1, "",
apicontract.NewAVCreateItemDocsResultError(apicontract.AVUnavailableNotebook{UnavailableNotebook: true}))
} Prevention
- Always resolve notebook IDs from lsNotebooks instead of hard-coding them
- Refresh cached notebook IDs after any notebook add/remove
- Handle ErrBoxNotFound explicitly in API clients to surface 'unavailable notebook'
When it happens
Trigger: model.CreateAttributeViewItemDocs (or other notebook-consuming operations) is called with a boxID that has no matching notebook in the workspace, or a save-config resolution derives a notebook ID that does not exist; handlers at kernel/api/av.go:361 and kernel/api/av_contract_render.go:66 map it to AVUnavailableNotebook.
Common situations: Client caches a stale notebook ID after the notebook was deleted or its .si folder removed; typo'd or malformed notebook ID in an API call; notebook added on another profile/workspace; attribute view references a doc whose notebook was removed.
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
- block [ ] is not a sortable document
- boot appearance not found
- ErrBlockNotFound
- ErrBoxClosed
- ErrTreeNotFound
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/2563bd4b149693dd.
Report an issue: GitHub.
Appendix: 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 9f775e8a12)