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

  1. Re-read the file and recompute line numbers immediately before applying edits
  2. Verify start_line <= current_line_count + 1 (and prefer exact line targeting) before the call
  3. 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

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


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