{"record":{"id":"9b0b0ed4e96471e8","repo":"siyuan-note/siyuan","slug":"notebook-s-not-found-9b0b0e","errorCode":null,"errorMessage":"notebook [%s] not found","messagePattern":"notebook \\[(.+?)\\] not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/file.go","lineNumber":2918,"sourceCode":"\topenedBoxes := map[string]*Box{}\n\tfor _, box := range Conf.GetOpenedBoxes() {\n\t\topenedBoxes[box.ID] = box\n\t}\n\n\tnotebookPlans := make([]*notebookSortPlan, 0, len(notebookSorts))\n\tnotebookIDs := map[string]struct{}{}\n\tfor _, item := range notebookSorts {\n\t\tif nil == item {\n\t\t\treturn ret, errors.New(\"notebook sort item must not be nil\")\n\t\t}\n\t\tif _, ok := notebookIDs[item.ID]; ok {\n\t\t\treturn ret, fmt.Errorf(\"duplicate notebook ID [%s]\", item.ID)\n\t\t}\n\t\tnotebookIDs[item.ID] = struct{}{}\n\n\t\tbox := boxes[item.ID]\n\t\tif nil == box {\n\t\t\treturn ret, fmt.Errorf(\"notebook [%s] not found\", item.ID)\n\t\t}\n\t\tnotebookPlans = append(notebookPlans, &notebookSortPlan{item: item, box: box})\n\t}\n\n\tdocPlans := make([]*docSortPlan, 0, len(docSorts))\n\tdocIDs := map[string]struct{}{}\n\tfor _, item := range docSorts {\n\t\tif nil == item {\n\t\t\treturn ret, errors.New(\"document sort item must not be nil\")\n\t\t}\n\t\tif _, ok := docIDs[item.ID]; ok {\n\t\t\treturn ret, fmt.Errorf(\"duplicate document ID [%s]\", item.ID)\n\t\t}\n\t\tdocIDs[item.ID] = struct{}{}\n\n\t\tbt := treenode.GetBlockTree(item.ID)\n\t\tif nil == bt || nil == openedBoxes[bt.BoxID] {\n\t\t\treturn ret, fmt.Errorf(\"document [%s] not found in opened and unlocked notebooks\", item.ID)","sourceCodeStart":2900,"sourceCodeEnd":2936,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/file.go#L2900-L2936","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the referenced notebook (listNotebooks / open API) before sorting, or drop it from the sort list","Refresh the notebook list and rebuild the sort payload from currently open notebooks only","Verify the ID is a notebook ID (matches a directory under data/) not a document block ID"],"exampleFix":"// before: sort stale cached list\ncustomSortNotebooks(cachedNotebookIDs)\n// after: intersect with currently open notebooks\nopen := map[string]bool{}\nfor _, b := range listNotebooks() { open[b.ID] = true }\nvalid := filter(cachedNotebookIDs, func(id string) bool { return open[id] })\ncustomSortNotebooks(valid)","handlingStrategy":"validation","validationCode":"const openIds = (await api.listNotebooks()).data.notebooks.map(n => n.id);\nconst valid = notebookSorts.filter(i => openIds.includes(i.id));","typeGuard":"const isOpenNotebook = (id, openSet) => openSet.has(id);","tryCatchPattern":"try { await api.sortNotebooks(notebookSorts); } catch (e) { if (String(e).includes('notebook [') && String(e).includes('] not found')) { await refreshOpenNotebooks(); retry(); } else { throw e; } }","preventionTips":["Build sort payloads from the currently open notebook list, not cached IDs","Open notebooks before including them in persisted order restoration","Distinguish notebook IDs from document block IDs in client state"],"tags":["go","notebook","not-found","stale-state"],"backgroundTag":"entity-not-found","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}