{"record":{"id":"085c9c42152f7639","repo":"siyuan-note/siyuan","slug":"cannot-move-document-s-into-itself","errorCode":null,"errorMessage":"cannot move document [%s] into itself","messagePattern":"cannot move document \\[(.+?)\\] into itself","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/file_tree_reorder.go","lineNumber":156,"sourceCode":"\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\"\n\t\t}\n\t\tsourceDocs, _, loadErr := ListDocTree(source.BoxID, sourceParent, util.SortModeCustom, false, true, int(^uint(0)>>1))\n\t\tif loadErr != nil {\n\t\t\treturn nil, loadErr\n\t\t}\n\t\tfor _, doc := range sourceDocs {\n\t\t\tif doc.ID == id {\n\t\t\t\tbyID[id] = doc\n\t\t\t\tbreak\n\t\t\t}\n\t\t}","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/file_tree_reorder.go#L138-L174","documentation":"ReorderDocTree refuses a drag-and-drop reorder when a source document's path contains (or equals) the target document's path, i.e. the user is trying to move a document into one of its own descendants or onto itself. Since custom ordering is stored per parent folder, nesting a document under itself would corrupt the document tree, so the operation is rejected up front.","triggerScenarios":"Calling ReorderDocTree (via the reorderDocs API) with a targetID whose .sy path equals the source document's path, or whose path has the source's path-minus-.sy plus \"/\" as a prefix, in the same notebook. In practice: dropping a document onto one of its own child documents or onto itself.","commonSituations":"A developer or script automating document reordering passes the wrong target ID; a UI bug lets users drop a parent document onto its own subtree; stale IDs after a rename/removal make the target resolve to a descendant of the source.","solutions":["Pick a different target document that is not a descendant of (or equal to) any source document.","Before calling the API, compare paths: reject when target path equals the source path or starts with strings.TrimSuffix(source.Path, \".sy\") + \"/\" in the same notebook.","Refresh document IDs/paths from the current tree if stale references caused the bad target."],"exampleFix":"// before\nawait reorderDocTree(boxID, [parentID], childID, position)\n// after\nif (targetPath === srcPath || targetPath.startsWith(srcPath.replace(/\\.sy$/, '') + '/')) {\n  throw new Error('cannot move a document into its own subtree')\n}\nawait reorderDocTree(boxID, [parentID], siblingID, position)","handlingStrategy":"validation","validationCode":"function isDescendantOrSelf(srcPath, targetPath) {\n  const base = srcPath.replace(/\\.sy$/, '')\n  return targetPath === srcPath || targetPath.startsWith(base + '/')\n}\n// call the API only if !isDescendantOrSelf(source.path, target.path) and same notebook","typeGuard":null,"tryCatchPattern":"try {\n  await reorderDocTree(boxID, sourceIDs, targetID, position)\n} catch (e) {\n  if (String(e.msg).includes('into itself')) showMsg('Cannot move a document into its own subtree')\n  else throw e\n}","preventionTips":["Validate target path against every source path before calling reorder","Only allow drop targets from a freshly fetched sibling list","Never reuse cached document IDs across rename/move operations"],"tags":["document-tree","invalid-argument-value","drag-and-drop","self-reference"],"backgroundTag":"invalid-argument-value","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"}