{"record":{"id":"59b3f471b26e9115","repo":"openai/openai-python","slug":"no-run-steps-found","errorCode":null,"errorMessage":"No run steps found","messagePattern":"No run steps found","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"src/openai/lib/streaming/_assistants.py","lineNumber":122,"sourceCode":"    def until_done(self) -> None:\n        \"\"\"Waits until the stream has been consumed\"\"\"\n        consume_sync_iterator(self)\n\n    def get_final_run(self) -> Run:\n        \"\"\"Wait for the stream to finish and returns the completed Run object\"\"\"\n        self.until_done()\n\n        if not self.__current_run:\n            raise RuntimeError(\"No final run object found\")\n\n        return self.__current_run\n\n    def get_final_run_steps(self) -> list[RunStep]:\n        \"\"\"Wait for the stream to finish and returns the steps taken in this run\"\"\"\n        self.until_done()\n\n        if not self.__run_step_snapshots:\n            raise RuntimeError(\"No run steps found\")\n\n        return [step for step in self.__run_step_snapshots.values()]\n\n    def get_final_messages(self) -> list[Message]:\n        \"\"\"Wait for the stream to finish and returns the messages emitted in this run\"\"\"\n        self.until_done()\n\n        if not self.__message_snapshots:\n            raise RuntimeError(\"No messages found\")\n\n        return [message for message in self.__message_snapshots.values()]\n\n    def __text_deltas__(self) -> Iterator[str]:\n        for event in self:\n            if event.event != \"thread.message.delta\":\n                continue\n\n            for content_delta in event.data.delta.content or []:","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/openai/openai-python/blob/9917c6e28e66e90e1227b3d223c06a8c5441515a/src/openai/lib/streaming/_assistants.py#L104-L140","documentation":"Raised by AssistantEventHandler.get_final_run_steps after stream completion when __run_step_snapshots is empty. Run steps are accumulated from thread.run.step.* events; if none arrived (the run produced no tool calls/details, or the stream never delivered run-step events), the dict stays empty and this error is thrown.","triggerScenarios":"Calling get_final_run_steps() on a simple run that only produced a text message (no tool steps), or on a stream that terminated before any thread.run.step.* events were emitted; also when custom on_event overrides skip the accumulate_event call.","commonSituations":"Assistants v2 streaming where the model answered directly with no tools; custom handler subclasses overriding on_event without calling super(); interrupted or cancelled runs.","solutions":["Treat empty steps as valid: wrap in try/except RuntimeError and use an empty list","If you override event callbacks in a subclass, call super().on_event(event) (or accumulate_event) so snapshots are recorded","Verify with get_final_run() that the run actually completed successfully","Check that tool use was actually expected for this run"],"exampleFix":"# before\nsteps = stream.get_final_run_steps()\n\n# after\ntry:\n    steps = stream.get_final_run_steps()\nexcept RuntimeError:\n    steps = []  # run had no tool steps","handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"try:\n    steps = stream.get_final_run_steps()\nexcept RuntimeError:\n    steps = []  # no tool steps in this run","preventionTips":["Call super().on_event(event) in custom handler overrides","Expect empty steps for tool-free runs","Check run status before requesting derived results"],"tags":["assistants","streaming","run-steps","python"],"backgroundTag":"stream-missing-final-event","analyzedSha":"9917c6e28e66e90e1227b3d223c06a8c5441515a","analyzedAt":"2026-08-28T11:46:34.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}