{"record":{"id":"cfeee0b37a713d33","repo":"Aider-AI/aider","slug":"duplicate-action-for-file-path","errorCode":null,"errorMessage":"Duplicate action for file: {path}","messagePattern":"Duplicate action for file: (.+?)","errorType":"exception","errorClass":"DiffError","httpStatus":null,"severity":"error","filePath":"aider/coders/patch_coder.py","lineNumber":385,"sourceCode":"                        continue\n                    else:\n                        raise DiffError(f\"Conflicting actions for file: {path}\")\n                if path not in current_files:\n                    raise DiffError(\n                        f\"Delete File Error - file not found: {path}\"\n                    )  # Check against known files\n\n                patch.actions[path] = PatchAction(type=ActionType.DELETE, path=path)\n                continue\n\n            # ---------- ADD ---------- #\n            elif norm_line.startswith(\"*** Add File: \"):\n                path = norm_line[len(\"*** Add File: \") :].strip()\n                index += 1\n                if not path:\n                    raise DiffError(\"Add File action missing path.\")\n                if path in patch.actions:\n                    raise DiffError(f\"Duplicate action for file: {path}\")\n                # Check if file exists in the context provided (should not for Add).\n                # Note: We only have needed files, a full check requires FS access.\n                # if path in current_files:\n                #     raise DiffError(f\"Add File Error - file already exists: {path}\")\n\n                action, index = self._parse_add_file_content(lines, index)\n                action.path = path  # Ensure path is set\n                patch.actions[path] = action\n                continue\n\n            # If we are here, the line is unexpected\n            # Allow blank lines between actions\n            if not norm_line.strip():\n                index += 1\n                continue\n\n            raise DiffError(f\"Unknown or misplaced line while parsing patch: {line}\")\n","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/Aider-AI/aider/blob/5dc9490bb35f9729ef2c95d00a19ccd30c26339c/aider/coders/patch_coder.py#L367-L403","documentation":"Raised during patch parsing when an '*** Add File: <path>' block uses a path that already has an entry in patch.actions. Unlike deletes (where exact duplicates are ignored with a warning), add actions are strictly unique per path.","triggerScenarios":"Two '*** Add File: same.py' blocks in one patch; an '*** Update File: same.py' earlier in the patch followed by an Add for the same path.","commonSituations":"Model emits the new file twice (often when the content is long and it restarts); concatenated retries in one response; add-after-update confusion in model output.","solutions":["Merge the two Add blocks into one, keeping the intended content","Remove the earlier action for that path if the file should only be added","Retry the edit so the model produces one action per file"],"exampleFix":"// before\n*** Add File: a.py\n+one\n*** Add File: a.py\n+two\n\n// after\n*** Add File: a.py\n+one\n+two\n","handlingStrategy":"validation","validationCode":"from collections import Counter\n\ndef no_duplicate_adds(patch_text: str) -> bool:\n    adds = [l[len(\"*** Add File: \"):].strip() for l in patch_text.splitlines()\n            if l.startswith(\"*** Add File: \")]\n    acts = [l.split(\": \", 1)[1].strip() for l in patch_text.splitlines()\n            if l.startswith(\"*** \") and \": \" in l]\n    return max(Counter(acts).values(), default=0) <= 1 and not (set(adds) & (set(acts) - set(adds)))","typeGuard":null,"tryCatchPattern":"try:\n    edits = coder.get_edits(reply)\nexcept DiffError as e:\n    if \"Duplicate action for file\" in str(e):\n        reply = merge_duplicate_add_blocks(reply)\n        edits = coder.get_edits(reply)\n    else:\n        raise","preventionTips":["Ask for one action block per file and merge content yourself if needed","Detect repeated '*** Add File:' headers in generated patches before parsing","Keep patches small — long patches invite the model to restart and duplicate"],"tags":["aider","patch","duplicate","parsing"],"backgroundTag":null,"analyzedSha":"5dc9490bb35f9729ef2c95d00a19ccd30c26339c","analyzedAt":"2026-08-15T05:40:10.498Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}