infiniflow/ragflow · error · RuntimeError

DATA_ERROR

DATA_ERROR

Error message

The folder is already in the target location. There is no need to move it.

What it means

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.

Source

Thrown at api/apps/services/file_api_service.py:513

        for f in FileService.query(name=new_name, parent_id=target_parent_id):
            if f.name == new_name:
                return False, "Duplicated file name in the same folder."

    if dest_folder:
        for file in files:
            if file.type == FileType.FOLDER.value and file.id == dest_folder.id:
                return False, "Cannot move a folder to itself."
        # Check if any source folder is an ancestor of the destination folder
        # to prevent infinite recursion in _move_entry_recursive
        dest_ancestors = FileService.get_all_parent_folders(dest_folder.id)
        dest_ancestor_ids = {f.id for f in dest_ancestors}
        for file in files:
            if file.type == FileType.FOLDER.value and file.id in dest_ancestor_ids:
                return False, "Cannot move a folder into its own subfolder."

    def _move_entry_recursive(source_file_entry, dest_folder_entry, override_name=None):
        if source_file_entry.id == dest_folder_entry.id:
            raise RuntimeError("The folder is already in the target location. There is no need to move it.")
        effective_name = override_name or source_file_entry.name

        if source_file_entry.type == FileType.FOLDER.value:
            existing_folder = FileService.query(name=effective_name, parent_id=dest_folder_entry.id)
            if existing_folder:
                if existing_folder[0].id == source_file_entry.id:
                    raise RuntimeError("The folder is already in the target location. There is no need to move it.")
                new_folder = existing_folder[0]
            else:
                new_folder = FileService.insert(
                    {
                        "id": get_uuid(),
                        "parent_id": dest_folder_entry.id,
                        "tenant_id": source_file_entry.tenant_id,
                        "created_by": source_file_entry.tenant_id,
                        "name": effective_name,
                        "location": "",
                        "size": 0,

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Filter the destination folder id (and its descendants) out of the source file list before calling the move API
  2. Run the move with only file ids plus folders that are genuinely outside the destination subtree
  3. If it persists, audit folder parent_id chains for cycles (SELECT id, parent_id and walk ancestors)
  4. Refresh the file tree in the UI and re-select — a stale tree often contains the destination in the selection

Example fix

# before
move(src_file_ids=[dest_id, *child_ids], dest_id=dest_id)

# after
src_ids = [fid for fid in child_ids if fid != dest_id]
move(src_file_ids=src_ids, dest_id=dest_id)
Defensive patterns

Strategy: validation

Validate before calling

# before move: dest must not appear in sources or their ancestor chain
src_ids = [f for f in src_ids if f != dest_id]
# if ancestor map is available client-side, also drop descendants of dest

Try / catch

try:
    move(src_ids, dest_id)
except RuntimeError as e:
    if "already in the target location" in str(e):
        pass  # no-op: treat as success after verifying parent_id == dest_id
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/c7ef6c5ce546371b. Report an issue: GitHub.