openai/openai-python · error · RuntimeError
No final run object found
Error message
No final run object found
What it means
Raised by AssistantEventHandler.get_final_run after the stream is fully consumed. It means the stream completed without the handler ever storing a Run object in __current_run, which normally happens when a thread.run.* event carrying run data is processed. Typically the run never actually started or the stream ended before any run snapshot arrived.
Source
Thrown at src/openai/lib/streaming/_assistants.py:113
def close(self) -> None:
"""
Close the response and release the connection.
Automatically called when the context manager exits.
"""
if self.__stream:
self.__stream.close()
def until_done(self) -> None:
"""Waits until the stream has been consumed"""
consume_sync_iterator(self)
def get_final_run(self) -> Run:
"""Wait for the stream to finish and returns the completed Run object"""
self.until_done()
if not self.__current_run:
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")View on GitHub (pinned to 9917c6e28e)
Solutions
- Inspect the raw events: override on_event or iterate stream to see which thread.run.* events actually arrived
- Verify thread_id and assistant_id are valid and the run was accepted (check for APIError during streaming)
- If you need resilience, call get_final_run inside try/except RuntimeError and fall back to client.beta.threads.runs.retrieve(run_id)
- Upgrade the SDK - older builds had gaps in run event accumulation
Example fix
# before
run = stream.get_final_run()
# after
try:
run = stream.get_final_run()
except RuntimeError:
run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id) Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
try:
run = stream.get_final_run()
except RuntimeError as e:
if "No final run object" in str(e):
run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id) Prevention
- Verify thread_id and assistant_id before starting the run
- Log raw events during development to confirm run events arrive
- Handle APIError raised while iterating the stream
When it happens
Trigger: Calling stream.get_final_run() on an Assistants v2 run stream that produced no thread.run.created/queued/in_progress events - e.g. streaming with an invalid assistant_id or thread_id where the server closes the stream early, or consuming the stream after it errored client-side so run events were never accumulated.
Common situations: Using the Assistants streaming API (v2 beta) and calling get_final_run after until_done; runs cancelled server-side immediately; malformed thread/assistant ids; the API silently terminating the SSE stream.
Related errors
- A single event handler cannot be shared between multiple str
- No run steps found
- No messages found
- Stream has not been started yet
- Encountered a message delta with no previous snapshot
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/cfa4429b545eba3c.
Report an issue: GitHub.