{"record":{"id":"cf9dfb3cb38178ef","repo":"Aider-AI/aider","slug":"conflicting-move-targets-for-file-path","errorCode":null,"errorMessage":"Conflicting move targets for file: {path}","messagePattern":"Conflicting move targets for file: (.+?)","errorType":"exception","errorClass":"DiffError","httpStatus":null,"severity":"error","filePath":"aider/coders/patch_coder.py","lineNumber":342,"sourceCode":"                if path not in current_files:\n                    raise DiffError(f\"Update File Error - missing file content for: {path}\")\n\n                file_content = current_files[path]\n\n                existing_action = patch.actions.get(path)\n                if existing_action is not None:\n                    # Merge additional UPDATE block into the existing one\n                    if existing_action.type != ActionType.UPDATE:\n                        raise DiffError(f\"Conflicting actions for file: {path}\")\n\n                    new_action, index, fuzz = self._parse_update_file_sections(\n                        lines, index, file_content\n                    )\n                    existing_action.chunks.extend(new_action.chunks)\n\n                    if move_to:\n                        if existing_action.move_path and existing_action.move_path != move_to:\n                            raise DiffError(f\"Conflicting move targets for file: {path}\")\n                        existing_action.move_path = move_to\n                    fuzz_accumulator += fuzz\n                else:\n                    # First UPDATE block for this file\n                    action, index, fuzz = self._parse_update_file_sections(\n                        lines, index, file_content\n                    )\n                    action.path = path\n                    action.move_path = move_to\n                    patch.actions[path] = action\n                    fuzz_accumulator += fuzz\n                continue\n\n            # ---------- DELETE ---------- #\n            elif norm_line.startswith(\"*** Delete File: \"):\n                path = norm_line[len(\"*** Delete File: \") :].strip()\n                index += 1\n                if not path:","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/Aider-AI/aider/blob/5dc9490bb35f9729ef2c95d00a19ccd30c26339c/aider/coders/patch_coder.py#L324-L360","documentation":"Raised by PatchCoder._parse_patch_text when merging a repeated UPDATE block for the same file: a '*** Move to:' target is given, but the existing action already has a different move_path. A file cannot be renamed to two destinations in one patch.","triggerScenarios":"Two '*** Update File: path' blocks for the same path, each carrying a '*** Move to:' with a different target — the second merge detects existing_action.move_path != move_to and raises.","commonSituations":"Model re-deciding the rename mid-patch; duplicated update sections from generation stutter; edits produced by concatenating two independently generated patches.","solutions":["Keep a single '*** Move to:' destination per file across the whole patch (or none).","Consolidate repeated update blocks for the same file into one block.","If two renames are genuinely needed, they are contradictory — pick one and delete the other.","Return the error to the model for a corrected, deduplicated patch."],"exampleFix":"# before\n*** Update File: a.py\n*** Move to: b.py\n@@\n context\n*** Update File: a.py\n*** Move to: c.py\n@@\n context\n*** End Patch\n\n# after\n*** Update File: a.py\n*** Move to: b.py\n@@\n context\n@@\n more context\n*** End Patch","handlingStrategy":"validation","validationCode":"from collections import defaultdict\nimport re\n\ndef conflicting_move_targets(patch_text: str) -> dict[str, set[str]]:\n    current, moves = None, defaultdict(set)\n    for l in patch_text.splitlines():\n        s = l.strip()\n        if s.startswith(\"*** Update File: \"):\n            current = s[len(\"*** Update File: \"):].strip()\n        elif s.startswith(\"*** Move to: \") and current:\n            moves[current].add(s[len(\"*** Move to: \"):].strip())\n    return {p: t for p, t in moves.items() if len(t) > 1}  # non-empty → pick one target","typeGuard":null,"tryCatchPattern":"try:\n    coder.get_edits(patch_text)\nexcept ValueError as e:\n    if \"Conflicting move targets for file:\" in str(e):\n        path = str(e).split(\"Conflicting move targets for file:\")[-1].strip()\n        patch_text = keep_single_move_target(patch_text, path)\n        coder.get_edits(patch_text)\n    else:\n        raise","preventionTips":["Emit at most one '*** Move to:' per file across the entire patch; merge repeated update blocks into one.","When the model changes its mind about a rename, delete the earlier Move-to, don't add a second.","Lint patches for duplicate move targets before applying."],"tags":["aider","patch-format","parsing","rename","conflict"],"backgroundTag":null,"analyzedSha":"5dc9490bb35f9729ef2c95d00a19ccd30c26339c","analyzedAt":"2026-08-15T05:40:10.498Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}