Aider-AI/aider · error · DiffError
ADD change for {action.path} has no content
Error message
ADD change for {action.path} has no content What it means
Defensive guard in apply_edits(): an ADD PatchAction has new_content is None. The parser always sets new_content (even to empty string), so hitting this means the PatchAction was constructed manually or by a modified code path with missing content.
Source
Thrown at aider/coders/patch_coder.py:572
return
# Group edits by original path? Not strictly needed if processed sequentially.
# Edits are now List[Tuple[str, PatchAction]]
for _path_tuple_element, action in edits:
# action is the PatchAction object
# action.path is the canonical path within the action logic
full_path = self.abs_root_path(action.path)
path_obj = pathlib.Path(full_path)
try:
if action.type == ActionType.ADD:
# Check existence *before* writing
if path_obj.exists():
raise DiffError(f"ADD Error: File already exists: {action.path}")
if action.new_content is None:
# Parser should ensure this doesn't happen
raise DiffError(f"ADD change for {action.path} has no content")
self.io.tool_output(f"Adding {action.path}")
path_obj.parent.mkdir(parents=True, exist_ok=True)
# Ensure single trailing newline, matching reference behavior
content_to_write = action.new_content
if not content_to_write.endswith("\n"):
content_to_write += "\n"
self.io.write_text(full_path, content_to_write)
elif action.type == ActionType.DELETE:
self.io.tool_output(f"Deleting {action.path}")
if not path_obj.exists():
self.io.tool_warning(
f"DELETE Warning: File not found, skipping: {action.path}"
)
else:
path_obj.unlink()
View on GitHub (pinned to 5dc9490bb3)
Solutions
- Always set new_content (use "" for an empty file) when constructing ADD actions
- If new_content is Optional in your code, default it to "" before apply_edits
- Check for accidental mutation of action.new_content between parse and apply
Example fix
# before PatchAction(type=ActionType.ADD, path="a.txt") # after PatchAction(type=ActionType.ADD, path="a.txt", new_content="")
Defensive patterns
Strategy: type-guard
Validate before calling
def add_actions_have_content(actions) -> bool:
return all(a.new_content is not None for a in actions if a.type.name == "ADD") Type guard
def is_valid_add_action(action) -> bool:
return (
action.type.name == "ADD"
and isinstance(action.path, str)
and action.path != ""
and isinstance(action.new_content, str)
) Try / catch
try:
coder.apply_edits(edits)
except ValueError as e:
if "has no content" in str(e):
edits = [a if a.type.name != "ADD" else replace(a, new_content=a.new_content or "") for a in edits]
coder.apply_edits(edits)
else:
raise Prevention
- Default new_content to '' when constructing ADD actions
- Prefer generating actions via the parser instead of building PatchAction by hand
- Assert invariants on programmatically built actions before apply
When it happens
Trigger: Programmatically building PatchAction(type=ADD, path=...) without new_content and passing it to apply_edits; deserializing actions from JSON that dropped the new_content field.
Common situations: Custom automation wrapping PatchCoder; tests constructing actions by hand; code after a refactor that defaults new_content to None.
Related errors
- ADD Error: File already exists: {action.path}
- Unknown action type encountered: {action.type}
- {path}: Overlapping or out-of-order chunk detected. Current
- Delete File action missing path.
- Delete File Error - file not found: {path}
AI-assisted analysis of Aider-AI/aider@5dc9490bb3 (2026-08-15).
Data as JSON: /api/errors/c03eb9e69f136037.
Report an issue: GitHub.