OpenBMB/ChatDev · error · ValueError
end_line must be >= start_line - 1
Error message
end_line must be >= start_line - 1
What it means
After coercion, each edit must satisfy end_line >= start_line - 1. The -1 slack permits pure-deletion edits where end_line = start_line - 1 (delete starting at start_line with empty replacement); anything smaller means the range is inverted or nonsensical. This usually indicates swapped start/end or garbled diff math.
Source
Thrown at functions/function_calling/file.py:920
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", "")
if not isinstance(replacement, str):
raise ValueError("replacement must be a string")
normalized.append(
TextEdit(
start_line=start_line,
end_line=end_line,
replacement_lines=replacement.splitlines(),
)
)
normalized.sort(key=lambda edit: (edit.start_line, edit.end_line))
_validate_edit_ranges(normalized)
return normalized
def _build_single_edit(
start_line: int,View on GitHub (pinned to 4fb2db0ea9)
Solutions
- Check whether start_line and end_line are swapped and correct them
- For deletions, use end_line = start_line - 1 with the appropriate replacement semantics, or better, set end_line to the last line to delete
- Validate ordering (end_line >= start_line - 1) per edit before calling
Example fix
# before
apply_text_edits(path="a.py", edits=[{"start_line": 10, "end_line": 2, "replacement": "x"}])
# after
apply_text_edits(path="a.py", edits=[{"start_line": 2, "end_line": 10, "replacement": "x"}]) Defensive patterns
Strategy: validation
Validate before calling
for e in edits:
if e.get("end_line", e["start_line"]) < e["start_line"] - 1:
e["start_line"], e["end_line"] = e["end_line"], e["start_line"] # un-swap
apply_text_edits(path=path, edits=edits) Type guard
def ranges_ordered(edits) -> bool:
return all(
e.get("end_line", e["start_line"]) >= e["start_line"] - 1 for e in edits
) Try / catch
try:
apply_text_edits(path=path, edits=edits)
except ValueError as e:
if "end_line must be >= start_line - 1" in str(e):
raise ValueError(f"inverted range in edits: {edits}") from e
raise Prevention
- Compute ranges from one consistent diff source
- Sanity-check start <= end when building each edit
- Avoid hand-arithmetic on line ranges; derive them programmatically
When it happens
Trigger: Swapping start_line and end_line (start=10, end=2); decrementing end_line below start_line-1 during range arithmetic; expressing a deletion with end_line = start_line - 2.
Common situations: Diff parsers that emit ranges in file-order vs hunk-order inconsistently; LLM-generated edits with inverted ranges; code that clamps end_line incorrectly (e.g. min(end, start-2)).
Related errors
- at least one edit instruction is required
- each edit entry must be a mapping object
- start_line is required for each edit
- end_line must be an integer
- replacement must be a string
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/50e480ec44ce4e11.
Report an issue: GitHub.