openai/openai-python · warning · RuntimeError

No messages found

Error message

No messages found

What it means

Raised by AssistantEventHandler.get_final_messages after stream completion when __message_snapshots is empty. Messages are accumulated from thread.message.* events; if the run produced no message events (e.g. it was cancelled, failed, or only called tools), the snapshot dict is empty and this error surfaces.

Solutions

  1. Check the final run status via get_final_run() (or __current_run.status) before asking for messages
  2. Wrap in try/except RuntimeError and default to an empty list if absent messages are acceptable
  3. Ensure custom event overrides call super().on_event(event) so message snapshots accumulate
  4. Verify the thread had a user message and the run was not cancelled

Example fix

# before
messages = stream.get_final_messages()

# after
run = stream.get_final_run()
if run.status == "completed":
    messages = stream.get_final_messages()
else:
    messages = []
    print(f"run ended with status {run.status}")
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

null

Try / catch

try:
    messages = stream.get_final_messages()
except RuntimeError:
    messages = []

Prevention

When it happens

Trigger: Calling get_final_messages() on a run that emitted no thread.message.created/delta events - cancelled or failed runs, runs consisting only of tool steps, invalid inputs where the stream closes early, or a custom handler that skips accumulate_event.

Common situations: Assistants v2 streaming with runs that end in status cancelled/failed; handlers that override on_event without chaining; expecting a message from a run that only submitted tool outputs.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/3e7acf6d47d3fe4a. Report an issue: GitHub.

Appendix: source

Thrown at src/openai/lib/streaming/_assistants.py:131

            raise RuntimeError("No final run object found")

        return self.__current_run

    def get_final_run_steps(self) -> list[RunStep]:
        """Wait for the stream to finish and returns the steps taken in this run"""
        self.until_done()

        if not self.__run_step_snapshots:
            raise RuntimeError("No run steps found")

        return [step for step in self.__run_step_snapshots.values()]

    def get_final_messages(self) -> list[Message]:
        """Wait for the stream to finish and returns the messages emitted in this run"""
        self.until_done()

        if not self.__message_snapshots:
            raise RuntimeError("No messages found")

        return [message for message in self.__message_snapshots.values()]

    def __text_deltas__(self) -> Iterator[str]:
        for event in self:
            if event.event != "thread.message.delta":
                continue

            for content_delta in event.data.delta.content or []:
                if content_delta.type == "text" and content_delta.text and content_delta.text.value:
                    yield content_delta.text.value

    # event handlers

    def on_end(self) -> None:
        """Fires when the stream has finished.

        This happens if the stream is read to completion

View on GitHub (pinned to 9917c6e28e)