siyuan-note/siyuan · warning · ErrBoxUnindexed

notebook unindexed

Error message

notebook unindexed

What it means

Sentinel error ErrBoxUnindexed declared at tree.go:207 ('notebook unindexed'). Returned by indexTreeInFilesystem (tree.go:358) when a block is found on disk via findUnindexedTreePathInAllBoxes, the owning boxID is resolved, but that box exists ONLY in Conf.GetClosedBoxes() (i.e., the notebook is closed/unindexed) — Conf.Box(boxID) returns nil. It indicates the data exists but the notebook must be opened (indexed) first.

Source

Thrown at kernel/model/tree.go:207

			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
	}

	bt := treenode.GetBlockTreeInBox(id, boxID)
	if nil == bt && "" == boxID {
		// boxID 未知时(如通用打开入口),遍历所有已打开的加密笔记本查找
		for _, encBoxID := range treenode.GetOpenedEncryptedBoxIDs() {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Open the closed notebook (UI action or API) so it gets indexed, then retry the operation.
  2. Use errors.Is(err, model.ErrBoxUnindexed) to prompt 'notebook X is closed, open it to access this doc'.
  3. Distinguish from ErrBoxNotFound (notebook does not exist at all) and ErrIndexing (transient).

Example fix

// before — generic error handling
tree, err := LoadTreeByBlockIDWithReindex(id)
if err != nil { showError(err) }

// after — branch on sentinel
if errors.Is(err, model.ErrBoxUnindexed) {
    promptOpenNotebook()
}
Defensive patterns

Strategy: validation

Validate before calling

func boxIsIndexed(boxID string) bool {
    return model.Conf.Box(boxID) != nil // nil => closed/unindexed
}

Try / catch

_, err := model.LoadTreeByBlockIDWithReindex(id)
if errors.Is(err, model.ErrBoxUnindexed) {
    promptUserToOpenNotebookByBlock(id)
}

Prevention

When it happens

Trigger: A block lookup falls through to the filesystem fallback, finds the .sy file under a notebook that is currently CLOSED (listed in GetClosedBoxes, not GetOpenedBoxes). The code logs 'box [X] is closed', pushes a localized message (Conf.language(197)), and returns ErrBoxUnindexed. block.go API handler checks errors.Is(err, model.ErrBoxUnindexed) to inform the client.

Common situations: A closed encrypted notebook contains the referenced block; a notebook the user closed still has docs referenced by bookmarks/history/external links; the kernel rebooted and the notebook was not auto-opened.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/4a0480cd356e65ee. Report an issue: GitHub.