{"record":{"id":"c1d6723c7f15de05","repo":"microsoft/autogen","slug":"expected-str-or-bytes-got-type-patch-data","errorCode":null,"errorMessage":"Expected str or bytes, got {type(patch_data)}","messagePattern":"Expected str or bytes, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/memory/canvas/_text_canvas.py","lineNumber":146,"sourceCode":"        if from_content == \"\" and to_content == \"\":  # one (or both) revision ids not found\n            return \"\"\n        diff = difflib.unified_diff(\n            from_content.splitlines(keepends=True),\n            to_content.splitlines(keepends=True),\n            fromfile=f\"{filename}@r{from_revision}\",\n            tofile=f\"{filename}@r{to_revision}\",\n        )\n        return \"\".join(diff)\n\n    def apply_patch(self, filename: str, patch_data: Union[str, bytes, Any]) -> None:\n        \"\"\"Apply *patch_text* (unified diff) to the latest revision and save a new revision.\n\n        Uses the *unidiff* library to accurately apply hunks and validate context lines.\n        \"\"\"\n        if isinstance(patch_data, bytes):\n            patch_data = patch_data.decode(\"utf-8\")\n        if not isinstance(patch_data, str):\n            raise ValueError(f\"Expected str or bytes, got {type(patch_data)}\")\n        self._ensure_file(filename)\n        original_content = self.get_latest_content(filename)\n\n        if PatchSet is None:\n            raise ImportError(\n                \"The 'unidiff' package is required for patch application. Install with 'pip install unidiff'.\"\n            )\n\n        patch = PatchSet(patch_data)\n        # Our canvas stores exactly one file per patch operation so we\n        # use the first (and only) patched_file object.\n        if not patch:\n            raise ValueError(\"Empty patch text provided.\")\n        patched_file = patch[0]\n        working_lines = original_content.splitlines(keepends=True)\n        line_offset = 0\n        for hunk in patched_file:\n            # Calculate the slice boundaries in the *current* working copy.","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/memory/canvas/_text_canvas.py#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\ncanvas.apply_patch(\"f.txt\", diff_lines_list)\n# after\ncanvas.apply_patch(\"f.txt\", \"\\n\".join(diff_lines_list))","handlingStrategy":"type-guard","validationCode":"import json\nif not isinstance(patch_data, (str, bytes)):\n    patch_data = patch_data if isinstance(patch_data, str) else json.dumps(patch_data)\n# better: extract the raw diff string from tool output up front\nraw_diff = tool_call_output[\"diff\"] if isinstance(tool_call_output, dict) else tool_call_output","typeGuard":"def is_raw_patch_text(value) -> bool:\n    return isinstance(value, (str, bytes))","tryCatchPattern":null,"preventionTips":["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."],"tags":["autogen","canvas","type-validation","patching"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}