{"record":{"id":"96dca9c391eb480a","repo":"OpenBMB/ChatDev","slug":"at-least-one-edit-instruction-is-required","errorCode":null,"errorMessage":"at least one edit instruction is required","messagePattern":"at least one edit instruction is required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"functions/function_calling/file.py","lineNumber":903,"sourceCode":"def _render_snippet_with_line_numbers(\n    lines: Sequence[str],\n    start_line: int,\n    newline_style: str,\n    preserve_trailing_newline: bool,\n) -> str:\n    numbered: List[str] = []\n    for idx, line in enumerate(lines):\n        body = line.rstrip(\"\\r\\n\")\n        numbered.append(f\"{start_line + idx}:{body}\")\n    rendered = newline_style.join(numbered)\n    if preserve_trailing_newline and numbered:\n        rendered += newline_style\n    return rendered\n\n\ndef _normalize_edits(edits: Sequence[Mapping[str, Any]]) -> List[TextEdit]:\n    if not edits:\n        raise ValueError(\"at least one edit instruction is required\")\n    normalized: List[TextEdit] = []\n    for item in edits:\n        if not isinstance(item, Mapping):\n            raise ValueError(\"each edit entry must be a mapping object\")\n        try:\n            start_line = int(item[\"start_line\"])\n        except (KeyError, TypeError, ValueError) as exc:\n            raise ValueError(\"start_line is required for each edit\") from exc\n        end_line_raw = item.get(\"end_line\", start_line)\n        try:\n            end_line = int(end_line_raw)\n        except (TypeError, ValueError) as exc:\n            raise ValueError(\"end_line must be an integer\") from exc\n        if start_line < 1:\n            raise ValueError(\"start_line must be >= 1\")\n        if end_line < start_line - 1:\n            raise ValueError(\"end_line must be >= start_line - 1\")\n        replacement = item.get(\"replacement\", \"\")","sourceCodeStart":885,"sourceCodeEnd":921,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/functions/function_calling/file.py#L885-L921","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Skip the apply_text_edits call entirely when the edits list is empty","Ensure your edit-generation step (diff parsing, template diffing) always emits at least one edit or signals no-op","Default to early-return: if not edits: return unchanged result"],"exampleFix":"# before\napply_text_edits(path=\"a.py\", edits=[])\n# after\nif edits:\n    apply_text_edits(path=\"a.py\", edits=edits)","handlingStrategy":"validation","validationCode":"if not edits:\n    return {\"changed\": False}\napply_text_edits(path=path, edits=edits)","typeGuard":"def has_edits(edits) -> bool:\n    return bool(edits) and len(edits) > 0","tryCatchPattern":"try:\n    apply_text_edits(path=path, edits=edits)\nexcept ValueError as e:\n    if \"at least one edit\" in str(e):\n        return {\"changed\": False}\n    raise","preventionTips":["Short-circuit no-op diffs before calling","When parsing patches, treat zero hunks as 'file unchanged'","Assert non-empty edit list in debug builds"],"tags":["validation","text-edit","empty-list"],"backgroundTag":"empty-collection-argument","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}