{"record":{"id":"a6a1e032fe07f923","repo":"microsoft/autogen","slug":"file-filename-does-not-exist-on-the-canvas-cr","errorCode":null,"errorMessage":"File '{filename}' does not exist on the canvas; create it first.","messagePattern":"File '(.+?)' does not exist on the canvas; create it first\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/memory/canvas/_text_canvas.py","lineNumber":59,"sourceCode":"    # ----------------------------------------------------------------------------------\n\n    def __init__(self) -> None:\n        # For each file we keep an *ordered* list of FileRevision where the last\n        # element is the most recent.  Using a list keeps the memory footprint\n        # small and preserves order without any extra bookkeeping.\n        self._files: Dict[str, List[FileRevision]] = {}\n\n    # ----------------------------------------------------------------------------------\n    # Internal utilities\n    # ----------------------------------------------------------------------------------\n\n    def _latest_idx(self, filename: str) -> int:\n        \"\"\"Return the index (not revision number) of the newest revision.\"\"\"\n        return len(self._files.get(filename, [])) - 1\n\n    def _ensure_file(self, filename: str) -> None:\n        if filename not in self._files:\n            raise ValueError(f\"File '{filename}' does not exist on the canvas; create it first.\")\n\n    # ----------------------------------------------------------------------------------\n    # Revision inspection helpers\n    # ----------------------------------------------------------------------------------\n\n    def get_revision_content(self, filename: str, revision: int) -> str:  # NEW 🚀\n        \"\"\"Return the exact content stored in *revision*.\n\n        If the revision does not exist an empty string is returned so that\n        downstream code can handle the \"not found\" case without exceptions.\n        \"\"\"\n        for rev in self._files.get(filename, []):\n            if rev.revision == revision:\n                return rev.content\n        return \"\"\n\n    def get_revision_diffs(self, filename: str) -> List[str]:  # NEW 🚀\n        \"\"\"Return a *chronological* list of unified‑diffs for *filename*.","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/memory/canvas/_text_canvas.py#L41-L77","documentation":"TextCanvas is a revision-tracked file store; operations that modify or read an existing file call _ensure_file, which raises ValueError naming the missing filename. The file must be created via add_or_update_file before patching, diffing, or reading revisions of it.","triggerScenarios":"Calling apply_patch, get_diff, get_revision_content-dependent mutation paths, or other revision operations on a filename never created with add_or_update_file, or after the canvas was cleared/reset.","commonSituations":"Agent LLM emits a patch for a file it never created first; filename mismatch (leading './', case, different path spelling) between the create call and the patch call; assuming the canvas pre-seeds files.","solutions":["Create the file first with canvas.add_or_update_file(filename, content) before applying patches.","Normalize filenames (strip './', lowercase if appropriate) so create and patch use the identical key.","Check existence via get_latest_content(filename) != \"\" or an explicit membership check before patching."],"exampleFix":"# before\ncanvas.apply_patch(\"notes.md\", patch_text)\n# after\nif not canvas.get_latest_content(\"notes.md\"):\n    canvas.add_or_update_file(\"notes.md\", \"\")\ncanvas.apply_patch(\"notes.md\", patch_text)","handlingStrategy":"validation","validationCode":"if not canvas.get_latest_content(filename):\n    canvas.add_or_update_file(filename, \"\")  # ensure the file exists before patching\ncanvas.apply_patch(filename, patch_text)","typeGuard":"def canvas_has_file(canvas, filename: str) -> bool:\n    return canvas.get_latest_content(filename) != \"\"","tryCatchPattern":"try:\n    canvas.apply_patch(filename, patch_text)\nexcept ValueError as e:\n    if \"does not exist on the canvas\" in str(e):\n        canvas.add_or_update_file(filename, \"\")\n        canvas.apply_patch(filename, patch_text)\n    else:\n        raise","preventionTips":["Normalize filenames (strip './', fix case) before any canvas call.","Always create files with add_or_update_file before patching or diffing.","When driving the canvas from LLM tool calls, validate the tool schema enforces create-before-patch."],"tags":["autogen","canvas","files","state"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}