siyuan-note/siyuan · error

invalid box ID [ ]

Error message

invalid box ID [%s]

What it means

ensureBoxDoc0 validates that the given box ID looks like a SiYuan node ID (32-char lowercase hex, per ast.IsNodeIDPattern) before creating or locating the box's hidden document. The box ID here is a notebook identifier that must follow the node ID format; anything else is rejected immediately with this formatted message echoing the offending value. It is thrown before any disk or database lookups.

Solutions

  1. Pass a valid notebook ID (32 lowercase hex characters) obtained from Conf.GetBox / listNotebooks output
  2. Trim whitespace and normalize case of the box ID before calling
  3. If generating a new ID, use ast.NewNodeID() rather than a custom string

Example fix

// before
EnsureBoxDoc("my notebook")
// after
box := Conf.GetBox("20240101120000-abcdef0123456789")
if box != nil {
    EnsureBoxDoc(box.ID)
}
Defensive patterns

Strategy: validation

Validate before calling

function isValidBoxID(id) {
  return typeof id === "string" && /^[0-9]{14}-[0-9a-z]{16}$/.test(id);
}
if (!isValidBoxID(boxID)) throw new Error("refusing to call EnsureBoxDoc with invalid ID");

Type guard

const isBoxID = (v: unknown): v is string => typeof v === "string" && /^[0-9]{14}-[0-9a-z]{16}$/.test(v);

Prevention

When it happens

Trigger: Calling model.EnsureBoxDoc or createBox with a boxID string that is empty, contains invalid characters, or is otherwise not a valid ast node ID pattern.

Common situations: Scripts or plugins constructing a notebook ID manually instead of using one returned by listNotebooks; truncated or uppercased IDs from external tools; passing a human-readable notebook name where an ID is expected.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/a19632856e32a71c. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/box_doc.go:130

	var bt *treenode.BlockTree
	if "" == boxID {
		bt = treenode.GetBlockTree(id)
	} else {
		bt = treenode.GetBlockTreeInBox(id, boxID)
	}
	return nil != bt && IsBoxDoc(bt.BoxID, bt.RootID)
}

func EnsureBoxDoc(boxID string) (boxDocID string, err error) {
	createDocLock.Lock()
	defer createDocLock.Unlock()
	return ensureBoxDoc0(boxID)
}

// ensureBoxDoc0 的调用方必须持有 createDocLock。
func ensureBoxDoc0(boxID string) (boxDocID string, err error) {
	if !ast.IsNodeIDPattern(boxID) {
		return "", fmt.Errorf("invalid box ID [%s]", boxID)
	}

	box := Conf.GetBox(boxID)
	if nil == box {
		return "", ErrBoxNotFound
	}

	if !IsBoxDocEnabled() {
		return
	}
	boxDocID = boxID

	boxDocID, err = findBoxDoc(box)
	if err != nil {
		return "", err
	}
	created, changed := false, false
	if "" == boxDocID {

View on GitHub (pinned to 9f775e8a12)