OpenBMB/ChatDev · error · ValueError
start_line is beyond the end of the file
Error message
start_line is beyond the end of the file
What it means
When applying edits bottom-up, _apply_edits_in_place rejects any edit whose start_line exceeds the current line count + 1. Appending at end-of-file (start_line == count+1) is allowed, but beyond that the edit would leave a gap of nonexistent lines, so it fails. Typically caused by stale line numbers after the file shrank or was edited by another step.
Source
Thrown at functions/function_calling/file.py:964
"replacement": replacement if replacement is not None else "",
}
return [payload]
def _validate_edit_ranges(edits: Sequence[TextEdit]) -> None:
previous_range_end = 0
for edit in edits:
effective_end = max(edit.end_line, edit.start_line - 1)
if edit.start_line <= previous_range_end and previous_range_end > 0:
raise ValueError("edit ranges overlap; merge them before calling apply_text_edits")
previous_range_end = max(previous_range_end, effective_end)
def _apply_edits_in_place(lines: MutableSequence[str], edits: Sequence[TextEdit]) -> None:
for edit in reversed(edits):
current_line_count = len(lines)
if edit.start_line > current_line_count + 1:
raise ValueError("start_line is beyond the end of the file")
start_idx = min(edit.start_line - 1, current_line_count)
if start_idx > current_line_count:
raise ValueError("start_line is beyond the end of the file")
removal_count = max(edit.end_line - edit.start_line + 1, 0)
if removal_count > 0:
end_line = min(edit.end_line, len(lines))
removal_count = max(end_line - edit.start_line + 1, 0)
end_idx = start_idx + removal_count
lines[start_idx:end_idx] = edit.replacement_lines
def _resolve_newline_choice(preference: str, detected: str) -> str:
normalized = (preference or "").lower()
if normalized == "lf":
return "\n"
if normalized == "crlf":
return "\r\n"
if normalized == "cr":View on GitHub (pinned to 4fb2db0ea9)
Solutions
- Re-read the file and recompute line numbers immediately before applying edits
- Verify start_line <= current_line_count + 1 (and prefer exact line targeting) before the call
- Apply edits in a single batch from one consistent file snapshot instead of several rounds
Example fix
# before
apply_text_edits(path="a.py", edits=[{"start_line": 100, "replacement": "x"}]) # file has 20 lines
# after
content = read_file("a.py")
n = len(content.splitlines())
apply_text_edits(path="a.py", edits=[{"start_line": min(100, n + 1), "replacement": "x"}]) Defensive patterns
Strategy: validation
Validate before calling
n_lines = len(Path(ws, path).read_text().splitlines())
for e in edits:
e["start_line"] = min(e["start_line"], n_lines + 1)
apply_text_edits(path=path, edits=edits) Type guard
def within_file(edits, n_lines) -> bool:
return all(e["start_line"] <= n_lines + 1 for e in edits) Try / catch
try:
apply_text_edits(path=path, edits=edits)
except ValueError as e:
if "beyond the end of the file" in str(e):
raise RuntimeError(f"stale line numbers for {path}; re-read and retry") from e
raise Prevention
- Read the file and derive line numbers in the same tick as the edit
- Avoid concurrent writes (formatters, other agents) between read and apply
- Batch edits instead of multiple sequential applications
When it happens
Trigger: start_line=100 on a 20-line file; using line numbers from a newer/older version of the file than the one on disk; multiple sequential apply calls where earlier edits changed line counts and later edits weren't recomputed.
Common situations: TOCTOU between reading the file and applying edits; concurrent modifications by formatters/linters/other agents; line numbers computed against a buffer with unsaved extra content.
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
- end_line must be >= start_line - 1
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/bf5a485905da377a.
Report an issue: GitHub.