datawhalechina/hello-agents · error · PatchApplyError

Add File target already exists: {rel_path}

Error message

Add File target already exists: {rel_path}

What it means

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.

Source

Thrown at Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py:142

        backup_run_dir = self.backups_dir / datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_run_dir.mkdir(parents=True, exist_ok=True)

        # 初始化结果收集变量
        files_changed: List[str] = []  # 记录被修改的文件路径
        backups: List[str] = []  # 记录创建的备份文件路径

        # 遍历所有解析出的操作,逐个执行
        for kind, rel_path, payload in ops:
            # 安全检查:确保路径在仓库内,防止路径遍历攻击
            target = self._safe_path(rel_path)
            
            # 安全检查:确保文件后缀在允许的列表中
            self._enforce_suffix(target)

            if kind == "add":
                # 添加新文件操作
                if target.exists():
                    raise PatchApplyError(f"Add File target already exists: {rel_path}")
                # 创建父目录(如果不存在)
                target.parent.mkdir(parents=True, exist_ok=True)
                # 原子写入新文件内容
                self._atomic_write(target, payload)
                # 记录变更
                files_changed.append(rel_path)
                
            elif kind == "delete":
                # 删除文件操作
                if not target.exists():
                    raise PatchApplyError(f"Delete File target missing: {rel_path}")
                # 删除前先备份文件
                b = self._backup_file(target, backup_run_dir)
                backups.append(str(b))
                # 删除文件
                target.unlink()
                # 记录变更
                files_changed.append(rel_path)

View on GitHub (pinned to 606a07d341)

Solutions

  1. Change the operation to Update (with the proper update payload) if the file should be modified.
  2. Delete or move the existing file first if a fresh create is truly intended.
  3. If re-applying after a partial failure, restore from the executor's backup dir first, or check files_changed from the failed ApplyResult.
  4. Make apply idempotent client-side: check existence and choose add vs update accordingly.

Example fix

# before
patch = '*** Begin Patch\n*** Add File: src/new.py\n+...\n*** End Patch'  # but src/new.py exists

# after
import pathlib
op = 'Update File: src/new.py' if pathlib.Path('src/new.py').exists() else 'Add File: src/new.py'
Defensive patterns

Strategy: type-guard

Validate before calling

from pathlib import Path
if Path(repo_root, rel_path).exists():
    raise ValueError(f"{rel_path} already exists; use an update op, not add")

Type guard

from pathlib import Path

def choose_op(rel_path: str) -> str:
    """Return the patch op kind that will not conflict for this path."""
    return "Update File" if (Path(rel_path).is_file()) else "Add File"

Try / catch

try:
    result = executor.apply(patch_text)
except PatchApplyError as e:
    if "already exists" in str(e):
        # regenerate patch with Update ops for existing files, then re-apply
        ...  # note: earlier ops in this patch may already be applied
    raise

Prevention

When it happens

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

Common situations: Re-running a failed patch without cleanup; agent hallucinating that a file is absent; racing processes creating the file between planning and apply.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/b29eb709d07b5e0b. Report an issue: GitHub.