siyuan-note/siyuan · error

ErrBoxClosed

ErrBoxClosed

Error message

notebook closed

What it means

ErrBoxClosed is the sentinel error for a notebook that exists but is currently closed (not loaded) in the workspace. Operations that write to or read from a closed notebook return it so callers can prompt the user (or CLI) to open the notebook first.

Source

Thrown at kernel/model/tree.go:211

			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. Open the notebook first (UI right-click - Open, or CLI `notebook open --id <boxID>`) and retry the operation
  2. Check notebook state via /api/notebook/lsNotebooks and only operate on notebooks with closed == false
  3. In CLI/scripts, call the notebook open command before any doc write when the box reports closed

Example fix

// before
if err := writeDoc(boxID, path, title); err != nil { return err }
// after
if err := writeDoc(boxID, path, title); err != nil {
    if errors.Is(err, model.ErrBoxClosed) {
        return fmt.Errorf("notebook [%s] is closed; run `notebook open --id %s` first", boxID, boxID)
    }
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

if isNotebookClosed(boxID) {
    return fmt.Errorf("notebook %s is closed; open it first", boxID)
}

Try / catch

if errors.Is(err, model.ErrBoxClosed) {
    return fmt.Errorf("notebook [%s] is closed; run `notebook open --id %s` first", boxID, boxID)
}

Prevention

When it happens

Trigger: Writing a document or creating a daily note in a notebook whose state is 'closed'; CLI commands hitting a closed box, intercepted by formatNotebookWriteError which appends 'run `notebook open --id <id>`'; getOpenedBox failing to find the box among open notebooks.

Common situations: User closed a notebook in the UI but an automation/plugin/CLI still targets it; headless/CLI usage against a workspace where the notebook defaults to closed; daily-note job running while its notebook is closed.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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