{"record":{"id":"b29eb709d07b5e0b","repo":"datawhalechina/hello-agents","slug":"add-file-target-already-exists-rel-path","errorCode":null,"errorMessage":"Add File target already exists: {rel_path}","messagePattern":"Add File target already exists: (.+?)","errorType":"exception","errorClass":"PatchApplyError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py","lineNumber":142,"sourceCode":"        backup_run_dir = self.backups_dir / datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n        backup_run_dir.mkdir(parents=True, exist_ok=True)\n\n        # 初始化结果收集变量\n        files_changed: List[str] = []  # 记录被修改的文件路径\n        backups: List[str] = []  # 记录创建的备份文件路径\n\n        # 遍历所有解析出的操作，逐个执行\n        for kind, rel_path, payload in ops:\n            # 安全检查：确保路径在仓库内，防止路径遍历攻击\n            target = self._safe_path(rel_path)\n            \n            # 安全检查：确保文件后缀在允许的列表中\n            self._enforce_suffix(target)\n\n            if kind == \"add\":\n                # 添加新文件操作\n                if target.exists():\n                    raise PatchApplyError(f\"Add File target already exists: {rel_path}\")\n                # 创建父目录（如果不存在）\n                target.parent.mkdir(parents=True, exist_ok=True)\n                # 原子写入新文件内容\n                self._atomic_write(target, payload)\n                # 记录变更\n                files_changed.append(rel_path)\n                \n            elif kind == \"delete\":\n                # 删除文件操作\n                if not target.exists():\n                    raise PatchApplyError(f\"Delete File target missing: {rel_path}\")\n                # 删除前先备份文件\n                b = self._backup_file(target, backup_run_dir)\n                backups.append(str(b))\n                # 删除文件\n                target.unlink()\n                # 记录变更\n                files_changed.append(rel_path)","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py#L124-L160","documentation":"PatchApplyError raised when an '*** Add File' operation targets a path that already exists on disk. The executor treats Add as create-only to avoid clobbering existing content; updates must use the update operation. Raised before any write, and per-file: earlier operations in the same patch may already have been applied.","triggerScenarios":"A patch with '*** Add File: path' where path exists — typically because the agent thought the file was new, or the same patch is applied twice, or a prior partial apply left the file behind.","commonSituations":"Re-running a failed patch without cleanup; agent hallucinating that a file is absent; racing processes creating the file between planning and apply.","solutions":["Change the operation to Update (with the proper update payload) if the file should be modified.","Delete or move the existing file first if a fresh create is truly intended.","If re-applying after a partial failure, restore from the executor's backup dir first, or check files_changed from the failed ApplyResult.","Make apply idempotent client-side: check existence and choose add vs update accordingly."],"exampleFix":"# before\npatch = '*** Begin Patch\\n*** Add File: src/new.py\\n+...\\n*** End Patch'  # but src/new.py exists\n\n# after\nimport pathlib\nop = 'Update File: src/new.py' if pathlib.Path('src/new.py').exists() else 'Add File: src/new.py'","handlingStrategy":"type-guard","validationCode":"from pathlib import Path\nif Path(repo_root, rel_path).exists():\n    raise ValueError(f\"{rel_path} already exists; use an update op, not add\")","typeGuard":"from pathlib import Path\n\ndef choose_op(rel_path: str) -> str:\n    \"\"\"Return the patch op kind that will not conflict for this path.\"\"\"\n    return \"Update File\" if (Path(rel_path).is_file()) else \"Add File\"","tryCatchPattern":"try:\n    result = executor.apply(patch_text)\nexcept PatchApplyError as e:\n    if \"already exists\" in str(e):\n        # regenerate patch with Update ops for existing files, then re-apply\n        ...  # note: earlier ops in this patch may already be applied\n    raise","preventionTips":["Check target existence right before generating the patch, not from a stale file listing.","Never re-apply a partially failed patch wholesale; reconcile state first.","Use the executor's backups directory to restore after partial applies."],"tags":["python","patching","conflict","code-agent"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}