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

  1. List current notebooks (/api/notebook/lsNotebooks) and confirm the box ID exists; update the client's references to a valid notebook
  2. Reopen the workspace or rescan notebooks so the registry is refreshed if the notebook exists on disk but is not loaded
  3. Remove or correct the stale daily-note configuration under Settings - Daily Note if it points to a deleted notebook
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2563bd4b149693dd. Report an issue: GitHub.