siyuan-note/siyuan · error

notebook [ ] not found for document [ ]

Error message

notebook [%s] not found for document [%s]

What it means

Thrown during document-tree sorting (DocSort / ReorderDocTree path) after resolving each requested item to a block tree entry. The block exists and is a valid root document, but its notebook (box) cannot be found in the currently opened notebook set, so the sort plan cannot be built. The kernel refuses to sort documents whose parent notebook is closed, removed, or otherwise absent from Conf.Box.

Solutions

  1. Re-open the notebook containing the document (Conf.Box / notebook list API) and retry the sort
  2. Re-fetch the current document list so the IDs passed to the sort API are fresh
  3. Verify the notebook still exists in the workspace data directory and was not renamed/deleted
  4. Filter the sort request to drop documents whose notebooks are not currently opened

Example fix

// before
api.post('/api/filetree/docSort', {ids: staleIDs})
// after
const opened = (await api.post('/api/notebook/lsNotebooks')).data.notebooks
const valid = staleIDs.filter(id => opened.some(nb => nb.id === boxOf(id)))
api.post('/api/filetree/docSort', {ids: valid})
Defensive patterns

Strategy: validation

Validate before calling

// Go-style caller check before sorting
const nb = (await api.post('/api/notebook/lsNotebooks')).data.notebooks.find(n => n.id === boxID)
if (!nb) throw new Error(`notebook ${boxID} is not opened`)

Try / catch

try { await sortDocs(ids) } catch (e) { if (String(e.msg).includes('not found for document')) { await refreshNotebookList(); retry(); } else { throw e } }

Prevention

When it happens

Trigger: Calling the doc sorting API (e.g. /api/filetree/docSort or ReorderDocTree) with a document ID whose bt.BoxID is not among the currently opened notebooks (nil == boxes[bt.BoxID]). Happens when the notebook was closed, renamed, or removed between client-side listing and the sort call.

Common situations: Stale client state: UI still holds document IDs from a notebook that was closed or deleted in another window; syncing removed a notebook; a script passes IDs collected earlier against a fresh kernel instance with fewer notebooks open.

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/41a5589cf41e9854. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/file.go:2942

	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)
		}
		if bt.ID != bt.RootID || "d" != bt.Type || IsBoxDoc(bt.BoxID, bt.RootID) {
			return ret, fmt.Errorf("block [%s] is not a sortable document", item.ID)
		}
		if nil == boxes[bt.BoxID] {
			return ret, fmt.Errorf("notebook [%s] not found for document [%s]", bt.BoxID, item.ID)
		}
		docPlans = append(docPlans, &docSortPlan{item: item, boxID: bt.BoxID, parentPath: path.Dir(bt.Path)})
	}

	docGroups := map[string]*docSortGroup{}
	for _, plan := range docPlans {
		group := docGroups[plan.boxID]
		if nil == group {
			confPath := filepath.Join(util.DataDir, plan.boxID, ".siyuan", "sort.json")
			fullSortIDs, readErr := readSortConfMap(confPath)
			if readErr != nil {
				return ret, readErr
			}
			group = &docSortGroup{
				fullSortIDs: fullSortIDs,
				changed:     map[string]int{},
				parentSorts: map[string]map[string]int{},
			}

View on GitHub (pinned to 9f775e8a12)