{"record":{"id":"c7ef6c5ce546371b","repo":"infiniflow/ragflow","slug":"data-error","errorCode":"DATA_ERROR","errorMessage":"The folder is already in the target location. There is no need to move it.","messagePattern":"The folder is already in the target location\\. There is no need to move it\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":400,"severity":"error","filePath":"api/apps/services/file_api_service.py","lineNumber":513,"sourceCode":"        for f in FileService.query(name=new_name, parent_id=target_parent_id):\n            if f.name == new_name:\n                return False, \"Duplicated file name in the same folder.\"\n\n    if dest_folder:\n        for file in files:\n            if file.type == FileType.FOLDER.value and file.id == dest_folder.id:\n                return False, \"Cannot move a folder to itself.\"\n        # Check if any source folder is an ancestor of the destination folder\n        # to prevent infinite recursion in _move_entry_recursive\n        dest_ancestors = FileService.get_all_parent_folders(dest_folder.id)\n        dest_ancestor_ids = {f.id for f in dest_ancestors}\n        for file in files:\n            if file.type == FileType.FOLDER.value and file.id in dest_ancestor_ids:\n                return False, \"Cannot move a folder into its own subfolder.\"\n\n    def _move_entry_recursive(source_file_entry, dest_folder_entry, override_name=None):\n        if source_file_entry.id == dest_folder_entry.id:\n            raise RuntimeError(\"The folder is already in the target location. There is no need to move it.\")\n        effective_name = override_name or source_file_entry.name\n\n        if source_file_entry.type == FileType.FOLDER.value:\n            existing_folder = FileService.query(name=effective_name, parent_id=dest_folder_entry.id)\n            if existing_folder:\n                if existing_folder[0].id == source_file_entry.id:\n                    raise RuntimeError(\"The folder is already in the target location. There is no need to move it.\")\n                new_folder = existing_folder[0]\n            else:\n                new_folder = FileService.insert(\n                    {\n                        \"id\": get_uuid(),\n                        \"parent_id\": dest_folder_entry.id,\n                        \"tenant_id\": source_file_entry.tenant_id,\n                        \"created_by\": source_file_entry.tenant_id,\n                        \"name\": effective_name,\n                        \"location\": \"\",\n                        \"size\": 0,","sourceCodeStart":495,"sourceCodeEnd":531,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/apps/services/file_api_service.py#L495-L531","documentation":"Raised inside the recursive folder-move helper in file_api_service when the source folder entry's id equals the destination folder entry's id — i.e. the code is asked to move a folder into itself. This is a defensive guard: the earlier pre-checks (move-to-itself and move-into-own-subfolder) should normally catch this, so hitting it means an entry was reached during recursion whose destination is itself, indicating inconsistent parent/child state or a stale destination.","triggerScenarios":"POST move/rename where source_files includes the destination folder id itself (pre-check bypassed via mixed file/folder payloads), or where DB folder rows have cyclic parent_id references so the recursion re-enters the same folder. Also reachable when an existing same-name folder lookup returns the source itself.","commonSituations":"Frontends that send the whole current folder selection including the target; concurrent moves that create parent cycles; DB rows manually edited so parent_id points at a descendant; retries of a move that already completed.","solutions":["Filter the destination folder id (and its descendants) out of the source file list before calling the move API","Run the move with only file ids plus folders that are genuinely outside the destination subtree","If it persists, audit folder parent_id chains for cycles (SELECT id, parent_id and walk ancestors)","Refresh the file tree in the UI and re-select — a stale tree often contains the destination in the selection"],"exampleFix":"# before\nmove(src_file_ids=[dest_id, *child_ids], dest_id=dest_id)\n\n# after\nsrc_ids = [fid for fid in child_ids if fid != dest_id]\nmove(src_file_ids=src_ids, dest_id=dest_id)","handlingStrategy":"validation","validationCode":"# before move: dest must not appear in sources or their ancestor chain\nsrc_ids = [f for f in src_ids if f != dest_id]\n# if ancestor map is available client-side, also drop descendants of dest","typeGuard":null,"tryCatchPattern":"try:\n    move(src_ids, dest_id)\nexcept RuntimeError as e:\n    if \"already in the target location\" in str(e):\n        pass  # no-op: treat as success after verifying parent_id == dest_id\n    else:\n        raise","preventionTips":["Exclude the destination folder from the multi-select before dragging","Compare each source's parent_id with dest_id client-side and skip equals","Refresh the folder tree before bulk moves to avoid stale selections"],"tags":["file-management","folders","move","recursion"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}