{"record":{"id":"41a5589cf41e9854","repo":"siyuan-note/siyuan","slug":"notebook-s-not-found-for-document-s","errorCode":null,"errorMessage":"notebook [%s] not found for document [%s]","messagePattern":"notebook \\[(.+?)\\] not found for document \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/file.go","lineNumber":2618,"sourceCode":"\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)\n\t\t}\n\t\tif bt.ID != bt.RootID || \"d\" != bt.Type || IsBoxDoc(bt.BoxID, bt.RootID) {\n\t\t\treturn ret, fmt.Errorf(\"block [%s] is not a sortable document\", item.ID)\n\t\t}\n\t\tif nil == boxes[bt.BoxID] {\n\t\t\treturn ret, fmt.Errorf(\"notebook [%s] not found for document [%s]\", bt.BoxID, item.ID)\n\t\t}\n\t\tdocPlans = append(docPlans, &docSortPlan{item: item, boxID: bt.BoxID, parentPath: path.Dir(bt.Path)})\n\t}\n\n\tdocGroups := map[string]*docSortGroup{}\n\tfor _, plan := range docPlans {\n\t\tgroup := docGroups[plan.boxID]\n\t\tif nil == group {\n\t\t\tconfPath := filepath.Join(util.DataDir, plan.boxID, \".siyuan\", \"sort.json\")\n\t\t\tfullSortIDs, readErr := readSortConfMap(confPath)\n\t\t\tif readErr != nil {\n\t\t\t\treturn ret, readErr\n\t\t\t}\n\t\t\tgroup = &docSortGroup{\n\t\t\t\tfullSortIDs: fullSortIDs,\n\t\t\t\tchanged:     map[string]int{},\n\t\t\t\tparentSorts: map[string]map[string]int{},\n\t\t\t}","sourceCodeStart":2600,"sourceCodeEnd":2636,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/file.go#L2600-L2636","documentation":"Thrown by SetFileTreeSort when a document's block tree entry passes the openedBoxes check (the notebook is open) but the notebook is not found in the full boxes map (built from Conf.GetBoxes()). This is a defensive invariant check: openedBoxes is a subset of boxes, so under normal operation this branch is unreachable. If hit, it indicates a race condition where the notebook was deleted or its configuration was removed between building the two maps.","triggerScenarios":"An extremely narrow race: the document's notebook is returned by Conf.GetOpenedBoxes() (building openedBoxes) but is missing from Conf.GetBoxes() (building boxes) within the same SetFileTreeSort call. This can happen if a notebook is being deleted concurrently on another goroutine while the sort operation is validating.","commonSituations":"Concurrent notebook deletion while a sort operation is in flight; a corrupted or inconsistent workspace configuration where GetOpenedBoxes and GetBoxes disagree; very unlikely under normal single-user operation.","solutions":["Retry the sort operation — if the notebook was being deleted, it should stabilize after the deletion completes.","If the error persists, check workspace configuration consistency: ensure .siyuan/conf.json lists the notebook consistently.","As an API client, refresh the notebook list and re-submit the sort payload with only currently valid notebook/document IDs."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry on the rare race where notebook config is inconsistent mid-operation\nasync function setFileTreeSortSafe(notebookSorts, docSorts, maxRetries = 2) {\n  for (let i = 0; i <= maxRetries; i++) {\n    try {\n      return await post('/api/filetree/setFileTreeSort', { notebookSorts, docSorts })\n    } catch (e) {\n      if (e.message.includes('not found for document') && i < maxRetries) {\n        await sleep(500)\n        continue\n      }\n      throw e\n    }\n  }\n}","preventionTips":["This error indicates a race condition — retry after a brief delay.","Avoid concurrent notebook deletion and sort operations in the same workspace.","If the error persists, check workspace configuration consistency."],"tags":["race-condition","filetree","sort","notebook","internal-invariant"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}