{"record":{"id":"a2d1162bd46b1f2b","repo":"FoundationAgents/MetaGPT","slug":"invoice-file-not-uploaded","errorCode":null,"errorMessage":"Invoice file not uploaded","messagePattern":"Invoice file not uploaded","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"metagpt/roles/invoice_ocr_assistant.py","lineNumber":80,"sourceCode":"        super().__init__(**kwargs)\n        self.set_actions([InvoiceOCR])\n        self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)\n\n    async def _act(self) -> Message:\n        \"\"\"Perform an action as determined by the role.\n\n        Returns:\n            A message containing the result of the action.\n        \"\"\"\n        msg = self.rc.memory.get(k=1)[0]\n        todo = self.rc.todo\n        if isinstance(todo, InvoiceOCR):\n            self.origin_query = msg.content\n            invoice_path: InvoicePath = msg.instruct_content\n            file_path = invoice_path.file_path\n            self.filename = file_path.name\n            if not file_path:\n                raise Exception(\"Invoice file not uploaded\")\n\n            resp = await todo.run(file_path)\n            actions = list(self.actions)\n            if len(resp) == 1:\n                # Single file support for questioning based on OCR recognition results\n                actions.extend([GenerateTable, ReplyQuestion])\n                self.orc_data = resp[0]\n            else:\n                actions.append(GenerateTable)\n            self.set_actions(actions)\n            self.rc.max_react_loop = len(self.actions)\n            content = INVOICE_OCR_SUCCESS\n            resp = OCRResults(ocr_result=json.dumps(resp))\n        elif isinstance(todo, GenerateTable):\n            ocr_results: OCRResults = msg.instruct_content\n            resp = await todo.run(json.loads(ocr_results.ocr_result), self.filename)\n\n            # Convert list to Markdown format string","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/roles/invoice_ocr_assistant.py#L62-L98","documentation":"InvoiceOCRRole._act expects the incoming message's instruct_content (an InvoicePath pydantic model) to carry a non-empty file_path. If file_path is empty (Path('')), it raises a bare Exception before running OCR. Note the check happens after reading invoice_path.file_path, so it validates path presence, not file existence.","triggerScenarios":"Sending a Message to the InvoiceOCR role whose instruct_content is an InvoicePath with default/empty path, or a message built without proper instruct_content so the parsed path is empty.","commonSituations":"Frontend/upload step failed to attach the file path; message serialization dropped the path field; testing the role with a manually constructed empty InvoicePath.","solutions":["Ensure the upload flow sets a real path: InvoicePath(file_path=Path('/data/invoice.pdf')) before publishing the message","Validate the path is non-empty and the file exists before sending the message to the role","Catch the exception in the calling action and re-prompt the user for the file"],"exampleFix":"// before\nmsg = Message(content=\"ocr this\", instruct_content=InvoicePath())  # empty path -> Exception\n\n// after\nfrom pathlib import Path\nmsg = Message(content=\"ocr this\", instruct_content=InvoicePath(file_path=Path(\"/data/invoice.pdf\")))","handlingStrategy":"validation","validationCode":"invoice_path = msg.instruct_content\nif not getattr(invoice_path, \"file_path\", None):\n    raise ValueError(\"upload an invoice file before running OCR\")\nif not Path(invoice_path.file_path).is_file():\n    raise FileNotFoundError(invoice_path.file_path)","typeGuard":"from pathlib import Path\n\ndef has_invoice_file(msg) -> bool:\n    ic = getattr(msg, \"instruct_content\", None)\n    p = getattr(ic, \"file_path\", None)\n    return bool(p) and Path(p).is_file()","tryCatchPattern":"try:\n    await role.run(msg)\nexcept Exception as e:\n    if \"Invoice file not uploaded\" in str(e):\n        reply = await ask_user_for_file()  # re-request upload\n    else:\n        raise","preventionTips":["Validate file_path is non-empty and the file exists before publishing the OCR message","Make the upload UI reject empty submissions","Store InvoicePath with an absolute path to avoid cwd-dependent failures"],"tags":["ocr","invoice","validation","file-upload"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}