{"record":{"id":"2907c54d8631ac9a","repo":"siyuan-note/siyuan","slug":"notebook-s-not-found-2907c5","errorCode":null,"errorMessage":"notebook [%s] not found","messagePattern":"notebook \\[(.+?)\\] not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box.go","lineNumber":1118,"sourceCode":"\trequestedIndex := 0\n\tfor _, id := range currentIDs {\n\t\tif _, requested := requestedSet[id]; requested {\n\t\t\tret = append(ret, validRequestedIDs[requestedIndex])\n\t\t\trequestedIndex++\n\t\t} else {\n\t\t\tret = append(ret, id)\n\t\t}\n\t}\n\treturn\n}\n\nfunc saveNotebookCustomOrder(boxes map[string]*Box, orderedIDs []string) error {\n\toldSorts := map[string]int{}\n\twrittenIDs := []string{}\n\tfor i, id := range orderedIDs {\n\t\tbox := boxes[id]\n\t\tif nil == box {\n\t\t\treturn fmt.Errorf(\"notebook [%s] not found\", id)\n\t\t}\n\t\tboxConf := box.GetConf()\n\t\toldSorts[id] = boxConf.Sort\n\t\tnewSort := i + 1\n\t\tif boxConf.Sort == newSort {\n\t\t\tcontinue\n\t\t}\n\t\tboxConf.Sort = newSort\n\t\tif err := box.SaveConf(boxConf); nil != err {\n\t\t\tfor _, writtenID := range writtenIDs {\n\t\t\t\twrittenBox := boxes[writtenID]\n\t\t\t\twrittenConf := writtenBox.GetConf()\n\t\t\t\twrittenConf.Sort = oldSorts[writtenID]\n\t\t\t\tif rollbackErr := writtenBox.SaveConf(writtenConf); nil != rollbackErr {\n\t\t\t\t\tlogging.LogErrorf(\"rollback notebook [%s] sort failed: %s\", writtenID, rollbackErr)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err","sourceCodeStart":1100,"sourceCodeEnd":1136,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/box.go#L1100-L1136","documentation":"saveNotebookCustomOrder persists a user's custom notebook sort order by looking up each requested ID in the provided boxes map. This error means an ID in orderedIDs does not correspond to any currently loaded notebook, so reordering is aborted (with rollback of already-written sorts by callers).","triggerScenarios":"Calling ChangeBoxSort or ReorderNotebooks with an ordered ID list containing a notebook ID that is closed, already deleted, renamed on disk, or was never opened in this session; also hit in race conditions where a notebook is removed between listing and reordering.","commonSituations":"Two windows reordering notebooks concurrently; a client sending a stale notebook list after another session deleted the notebook; scripts hitting the reorder API with hardcoded IDs after notebooks were recreated with new IDs.","solutions":["Re-fetch the current notebook list and retry the reorder using only IDs from that list","Verify the notebook still exists in the workspace data/ directory and is open","Remove stale IDs from the ordered list before calling ChangeBoxSort/ReorderNotebooks","Avoid concurrent reorders from multiple windows/sessions"],"exampleFix":"// before\nids := []string{\"20240101120000-abcdefg\", \"stale-id\"}\nReorderNotebooks(ids)\n// after\nids = filterExistingNotebooks(ids) // keep only IDs from current ListNotebooks()\nReorderNotebooks(ids)","handlingStrategy":"validation","validationCode":"// Go: keep only IDs of currently open notebooks\nvalid := []string{}\nfor _, id := range orderedIDs {\n    if boxes[id] != nil {\n        valid = append(valid, id)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := ReorderNotebooks(ids); err != nil {\n    if strings.Contains(err.Error(), \"not found\") {\n        ids = refreshAndFilterIDs(ids) // re-list notebooks and retry once\n    }\n}","preventionTips":["Always derive the ID list from a fresh notebook listing","Avoid concurrent reorder operations","Never hardcode notebook IDs in scripts"],"tags":["go","notebook","sort-order","not-found"],"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"}