microsoft/autogen · error · ValueError
Expected str or bytes, got {type(patch_data)}
Error message
Expected str or bytes, got {type(patch_data)} What it means
apply_patch accepts a unified diff as str or bytes (bytes is UTF-8 decoded). Any other type for patch_data raises before parsing, guarding the unidiff parser from garbage input.
Source
Thrown at python/packages/autogen-ext/src/autogen_ext/memory/canvas/_text_canvas.py:146
if from_content == "" and to_content == "": # one (or both) revision ids not found
return ""
diff = difflib.unified_diff(
from_content.splitlines(keepends=True),
to_content.splitlines(keepends=True),
fromfile=f"{filename}@r{from_revision}",
tofile=f"{filename}@r{to_revision}",
)
return "".join(diff)
def apply_patch(self, filename: str, patch_data: Union[str, bytes, Any]) -> None:
"""Apply *patch_text* (unified diff) to the latest revision and save a new revision.
Uses the *unidiff* library to accurately apply hunks and validate context lines.
"""
if isinstance(patch_data, bytes):
patch_data = patch_data.decode("utf-8")
if not isinstance(patch_data, str):
raise ValueError(f"Expected str or bytes, got {type(patch_data)}")
self._ensure_file(filename)
original_content = self.get_latest_content(filename)
if PatchSet is None:
raise ImportError(
"The 'unidiff' package is required for patch application. Install with 'pip install unidiff'."
)
patch = PatchSet(patch_data)
# Our canvas stores exactly one file per patch operation so we
# use the first (and only) patched_file object.
if not patch:
raise ValueError("Empty patch text provided.")
patched_file = patch[0]
working_lines = original_content.splitlines(keepends=True)
line_offset = 0
for hunk in patched_file:
# Calculate the slice boundaries in the *current* working copy.View on GitHub (pinned to 027ecf0a37)
Solutions
- Pass the raw unified-diff string: join line lists with '\n', or extract the diff field from the tool response.
- Ensure the value is not None before calling; guard tool outputs at the boundary.
Example fix
# before
canvas.apply_patch("f.txt", diff_lines_list)
# after
canvas.apply_patch("f.txt", "\n".join(diff_lines_list)) Defensive patterns
Strategy: type-guard
Validate before calling
import json
if not isinstance(patch_data, (str, bytes)):
patch_data = patch_data if isinstance(patch_data, str) else json.dumps(patch_data)
# better: extract the raw diff string from tool output up front
raw_diff = tool_call_output["diff"] if isinstance(tool_call_output, dict) else tool_call_output Type guard
def is_raw_patch_text(value) -> bool:
return isinstance(value, (str, bytes)) Prevention
- Extract the raw unified-diff string from tool/LLM payloads before calling apply_patch.
- Join line lists with newlines instead of passing the list itself.
When it happens
Trigger: Calling apply_patch(filename, patch_data) where patch_data is a list of diff lines, a dict from a parsed tool schema, None, or a PatchSet object.
Common situations: LLM tool output delivered as structured JSON instead of raw diff text; passing already-split lines; forgetting to extract the diff string from a tool-call response envelope.
Related errors
- Expected str or bytes, got {type(new_content)}
- Empty patch text provided.
- Expected Memory, List[Memory], or None, got {type(memory)}
- Unsupported tool type: {type(tool)}
- Unsupported handoff type: {type(handoff)}
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/c1d6723c7f15de05.
Report an issue: GitHub.