OpenBMB/ChatDev · error · ValueError
at least one edit instruction is required
Error message
at least one edit instruction is required
What it means
apply_text_edits normalizes its edits list via _normalize_edits, which requires a non-empty sequence. Passing an empty list (or None-like empty sequence) means there is nothing to apply, so the library rejects it rather than silently writing the file unchanged. Provide at least one edit instruction.
Source
Thrown at functions/function_calling/file.py:903
def _render_snippet_with_line_numbers(
lines: Sequence[str],
start_line: int,
newline_style: str,
preserve_trailing_newline: bool,
) -> str:
numbered: List[str] = []
for idx, line in enumerate(lines):
body = line.rstrip("\r\n")
numbered.append(f"{start_line + idx}:{body}")
rendered = newline_style.join(numbered)
if preserve_trailing_newline and numbered:
rendered += newline_style
return rendered
def _normalize_edits(edits: Sequence[Mapping[str, Any]]) -> List[TextEdit]:
if not edits:
raise ValueError("at least one edit instruction is required")
normalized: List[TextEdit] = []
for item in edits:
if not isinstance(item, Mapping):
raise ValueError("each edit entry must be a mapping object")
try:
start_line = int(item["start_line"])
except (KeyError, TypeError, ValueError) as exc:
raise ValueError("start_line is required for each edit") from exc
end_line_raw = item.get("end_line", start_line)
try:
end_line = int(end_line_raw)
except (TypeError, ValueError) as exc:
raise ValueError("end_line must be an integer") from exc
if start_line < 1:
raise ValueError("start_line must be >= 1")
if end_line < start_line - 1:
raise ValueError("end_line must be >= start_line - 1")
replacement = item.get("replacement", "")View on GitHub (pinned to 4fb2db0ea9)
Solutions
- Skip the apply_text_edits call entirely when the edits list is empty
- Ensure your edit-generation step (diff parsing, template diffing) always emits at least one edit or signals no-op
- Default to early-return: if not edits: return unchanged result
Example fix
# before
apply_text_edits(path="a.py", edits=[])
# after
if edits:
apply_text_edits(path="a.py", edits=edits) Defensive patterns
Strategy: validation
Validate before calling
if not edits:
return {"changed": False}
apply_text_edits(path=path, edits=edits) Type guard
def has_edits(edits) -> bool:
return bool(edits) and len(edits) > 0 Try / catch
try:
apply_text_edits(path=path, edits=edits)
except ValueError as e:
if "at least one edit" in str(e):
return {"changed": False}
raise Prevention
- Short-circuit no-op diffs before calling
- When parsing patches, treat zero hunks as 'file unchanged'
- Assert non-empty edit list in debug builds
When it happens
Trigger: Calling apply_text_edits(path, edits=[]) or edits=(); building edits from a diff/patch parser that produced zero hunks; filtering an edits list and accidentally emptying it before the call.
Common situations: Programmatic edit pipelines where a no-op diff (identical old/new content) yields an empty edit list; conditional code paths that accumulate edits but skip appending; LLM tool-call payloads with an empty edits array.
Related errors
- each edit entry must be a mapping object
- start_line is required for each edit
- end_line must be an integer
- end_line must be >= start_line - 1
- replacement must be a string
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/96dca9c391eb480a.
Report an issue: GitHub.