OpenBMB/ChatDev · error · ValueError

each edit entry must be a mapping object

Error message

each edit entry must be a mapping object

What it means

Each element of the edits sequence passed to apply_text_edits must be a mapping (dict-like) with start_line/end_line/replacement keys. _normalize_edits checks isinstance(item, Mapping) and raises ValueError when an entry is, e.g., a string, tuple, or list. This guards against malformed tool payloads before any file is touched.

Source

Thrown at functions/function_calling/file.py:907

    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", "")
        if not isinstance(replacement, str):
            raise ValueError("replacement must be a string")
        normalized.append(
            TextEdit(

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Ensure every edit entry is a dict with at least start_line and optionally end_line/replacement
  2. If JSON-serializing edits, use objects: {"start_line": 3, "end_line": 3, "replacement": "..."} not arrays
  3. Validate/normalize the payload shape before calling apply_text_edits

Example fix

# before
apply_text_edits(path="a.py", edits=["3: new text"])
# after
apply_text_edits(path="a.py", edits=[{"start_line": 3, "replacement": "new text"}])
Defensive patterns

Strategy: type-guard

Validate before calling

if not all(isinstance(e, dict) for e in edits):
    edits = [e if isinstance(e, dict) else dict(e) for e in edits]  # or reject
apply_text_edits(path=path, edits=edits)

Type guard

from collections.abc import Mapping

def is_edit_list(edits) -> bool:
    return isinstance(edits, (list, tuple)) and all(isinstance(e, Mapping) for e in edits)

Try / catch

try:
    apply_text_edits(path=path, edits=edits)
except ValueError as e:
    raise TypeError(f"malformed edits payload: {e}") from e

Prevention

When it happens

Trigger: Passing edits as a list of strings ('replace line 3'), tuples, or JSON where each entry is an array instead of an object; double-wrapping edits as [[{...}]] so inner items are lists; deserializing JSON with entries that are not objects.

Common situations: LLM tool-call arguments that encode edits as arrays; converting between tuple-based and dict-based edit representations; copy-pasting an example where the edit body was a string instead of an object.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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