FoundationAgents/MetaGPT · error · Exception

Invoice file not uploaded

Error message

Invoice file not uploaded

What it means

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.

Source

Thrown at metagpt/roles/invoice_ocr_assistant.py:80

        super().__init__(**kwargs)
        self.set_actions([InvoiceOCR])
        self._set_react_mode(react_mode=RoleReactMode.BY_ORDER.value)

    async def _act(self) -> Message:
        """Perform an action as determined by the role.

        Returns:
            A message containing the result of the action.
        """
        msg = self.rc.memory.get(k=1)[0]
        todo = self.rc.todo
        if isinstance(todo, InvoiceOCR):
            self.origin_query = msg.content
            invoice_path: InvoicePath = msg.instruct_content
            file_path = invoice_path.file_path
            self.filename = file_path.name
            if not file_path:
                raise Exception("Invoice file not uploaded")

            resp = await todo.run(file_path)
            actions = list(self.actions)
            if len(resp) == 1:
                # Single file support for questioning based on OCR recognition results
                actions.extend([GenerateTable, ReplyQuestion])
                self.orc_data = resp[0]
            else:
                actions.append(GenerateTable)
            self.set_actions(actions)
            self.rc.max_react_loop = len(self.actions)
            content = INVOICE_OCR_SUCCESS
            resp = OCRResults(ocr_result=json.dumps(resp))
        elif isinstance(todo, GenerateTable):
            ocr_results: OCRResults = msg.instruct_content
            resp = await todo.run(json.loads(ocr_results.ocr_result), self.filename)

            # Convert list to Markdown format string

View on GitHub (pinned to 11cdf466d0)

Solutions

  1. Ensure the upload flow sets a real path: InvoicePath(file_path=Path('/data/invoice.pdf')) before publishing the message
  2. Validate the path is non-empty and the file exists before sending the message to the role
  3. Catch the exception in the calling action and re-prompt the user for the file

Example fix

// before
msg = Message(content="ocr this", instruct_content=InvoicePath())  # empty path -> Exception

// after
from pathlib import Path
msg = Message(content="ocr this", instruct_content=InvoicePath(file_path=Path("/data/invoice.pdf")))
Defensive patterns

Strategy: validation

Validate before calling

invoice_path = msg.instruct_content
if not getattr(invoice_path, "file_path", None):
    raise ValueError("upload an invoice file before running OCR")
if not Path(invoice_path.file_path).is_file():
    raise FileNotFoundError(invoice_path.file_path)

Type guard

from pathlib import Path

def has_invoice_file(msg) -> bool:
    ic = getattr(msg, "instruct_content", None)
    p = getattr(ic, "file_path", None)
    return bool(p) and Path(p).is_file()

Try / catch

try:
    await role.run(msg)
except Exception as e:
    if "Invoice file not uploaded" in str(e):
        reply = await ask_user_for_file()  # re-request upload
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: Frontend/upload step failed to attach the file path; message serialization dropped the path field; testing the role with a manually constructed empty InvoicePath.

Related errors


AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14). Data as JSON: /api/errors/a2d1162bd46b1f2b. Report an issue: GitHub.