{"record":{"id":"fe0071ff7464f5f5","repo":"siyuan-note/siyuan","slug":"document-s-could-not-be-read","errorCode":null,"errorMessage":"document [%s] could not be read","messagePattern":"document \\[(.+?)\\] could not be read","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/file_tree_reorder.go","lineNumber":145,"sourceCode":"\t}\n\t// 隐藏文档和超过显示上限的文档也必须参与排序。\n\tdocs, _, err := ListDocTree(box.ID, listPath, mode, false, true, int(^uint(0)>>1))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbyID := map[string]*File{}\n\tcurrentIDs := make([]string, 0, len(docs))\n\tfor _, doc := range docs {\n\t\tbyID[doc.ID] = doc\n\t\tcurrentIDs = append(currentIDs, doc.ID)\n\t}\n\tsiblingIDs, err := loadSiblingCustomOrder(box.ID, parentDir, existingSorts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, id := range siblingIDs {\n\t\tif byID[id] == nil {\n\t\t\treturn nil, fmt.Errorf(\"document [%s] could not be read\", id)\n\t\t}\n\t}\n\tvar fromPaths []string\n\tfor _, id := range sourceIDs {\n\t\tsource := treenode.GetBlockTree(id)\n\t\tif !isSortableDocument(source) || Conf.Box(source.BoxID) == nil {\n\t\t\treturn nil, fmt.Errorf(\"source document [%s] is unavailable\", id)\n\t\t}\n\t\tif source.BoxID == target.BoxID && (target.Path == source.Path ||\n\t\t\tstrings.HasPrefix(target.Path, strings.TrimSuffix(source.Path, \".sy\")+\"/\")) {\n\t\t\treturn nil, fmt.Errorf(\"cannot move document [%s] into itself\", id)\n\t\t}\n\t\tif byID[id] != nil {\n\t\t\tcontinue\n\t\t}\n\t\tsourceParent := path.Dir(source.Path)\n\t\tif sourceParent != \"/\" {\n\t\t\tsourceParent += \".sy\"","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/file_tree_reorder.go#L127-L163","documentation":"ReorderDocTree loads the sibling documents of the target's parent (loadSiblingCustomOrder) and requires that every sibling ID it discovers is present in byID (the freshly loaded sibling records). If a sibling ID from the stored/existing order cannot be resolved to a readable document, the whole reorder is aborted with this error. It prevents persisting a sort order over a stale sibling set containing deleted or unreadable documents.","triggerScenarios":"The stored sort.json or block-tree sibling list contains an ID whose .sy file is missing, unreadable, or was removed from the index (deleted on another device, failed sync, partial index rebuild) while ReorderDocTree is computing the new order.","commonSituations":"sort.json left over from documents deleted via external file edits; sync conflicts leaving orphaned IDs in the custom order; index corruption after crash where the doc file is gone but the ID remains in stored order config.","solutions":["Delete or clean the stale entries in <data>/<boxID>/.siyuan/sort.json so the sibling list matches existing docs","Run a reindex: POST /api/filetree/refreshFiletree (or restart the kernel) to reconcile the index with disk","Restore the missing document (from SiYuan history or sync snapshot) if it should still exist","Check file permissions on the parent directory so the kernel can read all .sy files","Retry the reorder once the sibling list is consistent"],"exampleFix":"// before (sort.json references a deleted doc id 20240101120000-abcd123)\n{\"sorts\": {\"parentPath\": [\"20240101120000-abcd123\", \"20240101120001-defg456\"]}}\n// after (removed the orphaned id so reorder can proceed)\n{\"sorts\": {\"parentPath\": [\"20240101120001-defg456\"]}}","handlingStrategy":"validation","validationCode":"// Ensure stored custom order has no orphan ids before reordering\nconst siblings = await fetchPost('/api/filetree/listDocsByPath', {notebook: boxId, path: parentPath});\nconst live = new Set(siblings.data.files.map(f => f.id));\n// any id in sort.json not in `live` is a stale entry needing cleanup/reindex","typeGuard":null,"tryCatchPattern":"try {\n  await fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID, position});\n} catch (e) {\n  if (String(e).includes('could not be read')) {\n    await fetchPost('/api/filetree/refreshFiletree', {}); // reconcile index with disk, then retry\n  }\n}","preventionTips":["Never edit .sy files under data/ manually; deletions must go through the app or API","Run a filetree refresh/reindex after crash recovery or external file changes","Keep sort.json consistent by deleting docs via SiYuan so custom-order entries are cleaned up","Watch sync conflicts — restore missing docs from history if siblings disappear"],"tags":["document","not-found","index","reorder"],"backgroundTag":"record-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}