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

  1. Skip the apply_text_edits call entirely when the edits list is empty
  2. Ensure your edit-generation step (diff parsing, template diffing) always emits at least one edit or signals no-op
  3. 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

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


AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/96dca9c391eb480a. Report an issue: GitHub.