siyuan-note/siyuan · error

notebook [ ] not found

Error message

notebook [%s] not found

What it means

Notebook sort planning resolves each item's ID against the map of opened (and unlocked) notebooks. If the ID is not a currently opened notebook, it fails with "notebook [%s] not found". The kernel only sorts notebooks that are open in this session; closed or nonexistent notebooks are rejected.

Solutions

  1. Open the referenced notebook (listNotebooks / open API) before sorting, or drop it from the sort list
  2. Refresh the notebook list and rebuild the sort payload from currently open notebooks only
  3. Verify the ID is a notebook ID (matches a directory under data/) not a document block ID

Example fix

// before: sort stale cached list
customSortNotebooks(cachedNotebookIDs)
// after: intersect with currently open notebooks
open := map[string]bool{}
for _, b := range listNotebooks() { open[b.ID] = true }
valid := filter(cachedNotebookIDs, func(id string) bool { return open[id] })
customSortNotebooks(valid)
Defensive patterns

Strategy: validation

Validate before calling

const openIds = (await api.listNotebooks()).data.notebooks.map(n => n.id);
const valid = notebookSorts.filter(i => openIds.includes(i.id));

Type guard

const isOpenNotebook = (id, openSet) => openSet.has(id);

Try / catch

try { await api.sortNotebooks(notebookSorts); } catch (e) { if (String(e).includes('notebook [') && String(e).includes('] not found')) { await refreshOpenNotebooks(); retry(); } else { throw e; } }

Prevention

When it happens

Trigger: Calling the notebook sort API with an ID for a notebook that is closed, was removed, never existed, or whose ID string is truncated/typo'd; sorting a persisted list saved when more notebooks were open.

Common situations: Client caches notebook IDs from a previous session; notebook closed by another window between listing and sorting; hardcoded ID in a script after the notebook was deleted; mixing up notebook ID with document ID.

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@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/9b0b0ed4e96471e8. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/file.go:2918

	openedBoxes := map[string]*Box{}
	for _, box := range Conf.GetOpenedBoxes() {
		openedBoxes[box.ID] = box
	}

	notebookPlans := make([]*notebookSortPlan, 0, len(notebookSorts))
	notebookIDs := map[string]struct{}{}
	for _, item := range notebookSorts {
		if nil == item {
			return ret, errors.New("notebook sort item must not be nil")
		}
		if _, ok := notebookIDs[item.ID]; ok {
			return ret, fmt.Errorf("duplicate notebook ID [%s]", item.ID)
		}
		notebookIDs[item.ID] = struct{}{}

		box := boxes[item.ID]
		if nil == box {
			return ret, fmt.Errorf("notebook [%s] not found", item.ID)
		}
		notebookPlans = append(notebookPlans, &notebookSortPlan{item: item, box: box})
	}

	docPlans := make([]*docSortPlan, 0, len(docSorts))
	docIDs := map[string]struct{}{}
	for _, item := range docSorts {
		if nil == item {
			return ret, errors.New("document sort item must not be nil")
		}
		if _, ok := docIDs[item.ID]; ok {
			return ret, fmt.Errorf("duplicate document ID [%s]", item.ID)
		}
		docIDs[item.ID] = struct{}{}

		bt := treenode.GetBlockTree(item.ID)
		if nil == bt || nil == openedBoxes[bt.BoxID] {
			return ret, fmt.Errorf("document [%s] not found in opened and unlocked notebooks", item.ID)

View on GitHub (pinned to 9f775e8a12)