Skip to content

BUG: patch edit format cannot create new files: *** Add File fails with "File already exists" and leaves an empty file #5875

Open
Sarthak816/aider
#5

Description

@yifanxiong272

Issue

Summary

With --edit-format patch, a reply that creates a new file with *** Add File: <path> is always rejected with ADD Error: File already exists: <path>, and an empty file is left behind at that path. The patch system prompt tells the model to use exactly this marker for new files, so the patch format cannot create files at all.

Steps to reproduce

  1. pip install aider-chat==0.86.0 (no API key or network needed; litellm's mock_response supplies the reply).
  2. Save as repro.py:
# patch edit format: "*** Add File" cannot create a new file.
# Requires only `pip install aider-chat==0.86.0`; no API key or network
# (litellm's mock_response supplies the model reply).
import os
import tempfile
from pathlib import Path

from aider import __version__
from aider.coders import Coder
from aider.io import InputOutput
from aider.models import Model

os.chdir(tempfile.mkdtemp())
print("aider", __version__)

reply = """*** Begin Patch
*** Add File: hello.py
+def hello():
+    print("hello")
*** End Patch
"""

model = Model("gpt-4o")
model.extra_params = {"mock_response": reply}
coder = Coder.create(
    main_model=model,
    edit_format="patch",
    io=InputOutput(yes=True, pretty=False, fancy_input=False),
    use_git=False,
    stream=False,
)
coder.max_reflections = 0  # one attempt is enough to show the failure
coder.run(with_message="Create hello.py with a hello() function.")

path = Path("hello.py")
print("---")
print("hello.py exists:", path.exists())
print("hello.py content:", repr(path.read_text()) if path.exists() else None)
  1. Run python repro.py.

Actual output

aider 0.86.0
*** Begin Patch
*** Add File: hello.py
+def hello():
+    print("hello")
*** End Patch

Tokens: 10 sent, 20 received. Cost: $0.00023 message, $0.00023 session.

hello.py
The LLM did not conform to the edit format.
https://aider.chat/docs/troubleshooting/edit-errors.html

Error applying action 'ActionType.ADD' to hello.py: ADD Error: File already 
exists: hello.py
Only 0 reflections allowed, stopping.
---
hello.py exists: True
hello.py content: ''

main at 5dc9490b prints the same output (only the version line differs). With the default max_reflections, every retry fails the same way, because the empty file from the first attempt is still there.

Expected behavior

hello.py is created with the two lines from the patch.

The patch system prompt asks for this format when the model creates a file:

  • aider/coders/patch_prompts.py L153: "For Add actions, use the *** Add File: [path/to/new/file] marker, followed by the lines of the new file, each preceded by a plus sign +."
  • The worked example in the same prompt creates hello.py with *** Add File: hello.py (L95).

The other edit formats create new files through the same allowed_to_edit path and then write the new content into the file it creates.

Root cause

  1. Coder.apply_updates runs prepare_to_edit(edits) before apply_edits(edits) (base_coder.py L2296-L2304).
  2. prepare_to_edit calls allowed_to_edit(path). For a path that does not exist yet, allowed_to_edit confirms "Create new file?" and then calls utils.touch_file(full_path), which creates an empty file (base_coder.py L2206-L2224). In a git repo the new file is also git added (on main, when auto-commits are on).
  3. PatchCoder.apply_edits then handles the ADD action by checking path_obj.exists() and raising DiffError("ADD Error: File already exists: ...") (patch_coder.py L566-L569). The file always exists at this point because step 2 just created it.
  4. DiffError is a ValueError, so apply_updates reports the reply as malformed and reflects the error to the model. The empty file remains.

Possible fix direction

Make the ADD check see the file system as it was before prepare_to_edit, for example by recording the paths that allowed_to_edit touched and letting ADD write to such a path, or by accepting ADD when the target exists and is empty. A regression test that runs a mocked *** Add File reply through Coder.run would cover the full apply_updates sequence.

Version and model info

Aider: 0.86.0 (PyPI) and main@5dc9490bb35f9729ef2c95d00a19ccd30c26339c (0.86.3.dev0)
Edit format: patch (--edit-format patch)
Model: gpt-4o with litellm mock_response (no real model call)
Python: 3.12.13
Operating system: Ubuntu 22.04.5 LTS
litellm: 1.75.0 (0.86.0) / 1.82.3 (main)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions