{"record":{"id":"0c597390c3cf44bd","repo":"siyuan-note/siyuan","slug":"target-document-s-is-unavailable","errorCode":null,"errorMessage":"target document [%s] is unavailable","messagePattern":"target document \\[(.+?)\\] is unavailable","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/file_tree_reorder.go","lineNumber":111,"sourceCode":"\tinherited, err := ResolveDocTreeSortMode(boxID, parentPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif inherited == util.SortModeCustom {\n\t\treturn nil, nil\n\t}\n\treturn &mode, nil\n}\n\n// ReorderDocTree 在移动前检查完整列表，确认冲突后仅设置目标列表的排序方式。\nfunc ReorderDocTree(sourceIDs []string, targetID, position string, preview, removeSorts bool) (ret *DocTreeReorderResult, err error) {\n\tif err = validateReorderArgs(sourceIDs, targetID, position); err != nil {\n\t\treturn\n\t}\n\tFlushTxQueue()\n\ttarget := treenode.GetBlockTree(targetID)\n\tif !isSortableDocument(target) || Conf.Box(target.BoxID) == nil {\n\t\treturn nil, fmt.Errorf(\"target document [%s] is unavailable\", targetID)\n\t}\n\tbox := Conf.Box(target.BoxID)\n\tparentDir := path.Dir(target.Path)\n\tconfPath := filepath.Join(util.DataDir, box.ID, \".siyuan\", \"sort.json\")\n\texistingSorts, err := readSortConfMap(confPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlistPath := parentDir\n\tif listPath != \"/\" {\n\t\tlistPath += \".sy\"\n\t}\n\tmode, err := ResolveDocTreeSortMode(box.ID, listPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// 隐藏文档和超过显示上限的文档也必须参与排序。\n\tdocs, _, err := ListDocTree(box.ID, listPath, mode, false, true, int(^uint(0)>>1))","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/file_tree_reorder.go#L93-L129","documentation":"ReorderDocTree validates that the reorder target document exists in the block tree, is a sortable document, and belongs to a notebook currently known to the kernel (Conf.Box). If any of these fail, it returns this error instead of reordering. It protects against reordering around a target that is deleted, moved, corrupted in the index, or in a notebook that is closed.","triggerScenarios":"Calling ReorderDocTree (or reorderDocs API path) with targetID that has no block-tree record (deleted/unindexed doc), is not a sortable document (e.g. a special/system path), or whose notebook is closed or removed (Conf.Box returns nil).","commonSituations":"Drag-drop onto a document deleted by another client or sync between drag start and drop; notebook closed while the tree view still shows its docs; stale tree cache after bulk reorganization; targetID typo in API scripts.","solutions":["Confirm the target document exists and refresh: POST /api/filetree/getDoc with targetID","Re-open the target notebook (POST /api/notebook/openNotebook) if it was closed","Call POST /api/filetree/refreshFiletree or restart sync to rebuild the block-tree index, then retry","Verify targetID is a full 22-character block ID of an existing .sy document","Re-check the doc tree listing to obtain a valid current target ID before reordering"],"exampleFix":"// before (target deleted by sync between drag and drop)\nawait fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID: draggedOverID, position});\n// after (guard on live tree data)\nconst tree = await fetchPost('/api/filetree/listDocsByPath', {notebook, path: parentPath});\nif (!tree.data.files.some(f => f.id === draggedOverID)) {\n  return showError('Target document no longer exists');\n}\nawait fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID: draggedOverID, position});","handlingStrategy":"validation","validationCode":"async function canReorder(targetId) {\n  const r = await fetchPost('/api/filetree/getDocInfo', {id: targetId});\n  return r && r.data && r.data.id === targetId;\n}\nif (!(await canReorder(targetId))) await refreshFiletree();","typeGuard":"function isFullBlockId(v) { return typeof v === 'string' && /^[0-9]{14}-[a-z0-9]{7}$/.test(v); }","tryCatchPattern":"try {\n  await fetchPost('/api/filetree/reorderDocs', {sourceIDs, targetID, position});\n} catch (e) {\n  if (String(e).includes('target document') && String(e).includes('unavailable')) {\n    await fetchPost('/api/filetree/refreshFiletree', {});\n    showMsg('Target document is gone; tree refreshed', true);\n  }\n}","preventionTips":["Ensure the target notebook is open before reordering its documents","Refresh the filetree after any external edit/sync before reorder operations","Validate target IDs exist immediately before the reorder call","Avoid operating on documents mid-sync; wait for sync completion"],"tags":["document","not-found","validation","reorder"],"backgroundTag":"entity-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}