openai/openai-python · error · RuntimeError
Stream has not been started yet
Error message
Stream has not been started yet
What it means
Thrown by AssistantEventHandler.__stream__ when the internal generator is advanced before the handler has been bound to a real Stream via _init. __init__ eagerly creates self._iterator = self.__stream__(), but the generator body only runs on first next(); if iteration happens outside a with client...stream(...) block (which calls __enter__ -> _init), self.__stream is still None.
Source
Thrown at src/openai/lib/streaming/_assistants.py:406
if self._current_tool_call:
self.on_tool_call_done(self._current_tool_call)
self.on_run_step_done(event.data)
self.__current_run_step_id = None
elif event.event == "thread.created" or event.event == "thread.message.in_progress" or event.event == "error":
# currently no special handling
...
else:
# we only want to error at build-time
if TYPE_CHECKING: # type: ignore[unreachable]
assert_never(event)
self._current_event = None
def __stream__(self) -> Iterator[AssistantStreamEvent]:
stream = self.__stream
if not stream:
raise RuntimeError("Stream has not been started yet")
try:
for event in stream:
self._emit_sse_event(event)
yield event
except _timeout_exceptions() as exc:
self.on_timeout()
self.on_exception(exc)
raise
except Exception as exc:
self.on_exception(exc)
raise
finally:
self.on_end()
AssistantEventHandlerT = TypeVar("AssistantEventHandlerT", bound=AssistantEventHandler)View on GitHub (pinned to 9917c6e28e)
Solutions
- Always consume events/deltas inside the with (or async with) block returned by client.beta.threads.runs.stream / create_and_stream
- Do not call next() on handler or its text_deltas iterator before entering the context
- If you need the deltas, iterate stream.text_deltas on the stream object returned by the context manager, not on a bare handler
Example fix
# before
handler = MyHandler()
deltas = list(handler.text_deltas) # stream not started
# after
with client.beta.threads.runs.stream(..., event_handler=handler) as stream:
for delta in stream.text_deltas:
print(delta, end="") Defensive patterns
Strategy: validation
Validate before calling
def ensure_started(handler) -> None:
if getattr(handler, "_AssistantEventHandler__stream", None) is None:
raise RuntimeError("enter the stream context before iterating") Type guard
def handler_is_live(h) -> bool:
return getattr(h, "_AssistantEventHandler__stream", None) is not None Try / catch
try:
for delta in handler.text_deltas:
...
except RuntimeError as e:
if "not been started" in str(e):
# use the context-managed stream instead
... Prevention
- Only iterate inside the with block
- Prefer stream.text_deltas over handler.text_deltas
- Never call next() on a bare handler
When it happens
Trigger: Manually iterating handler.text_deltas or the handler itself without entering the stream context: next(handler) or for delta in handler.text_deltas before with client.beta.threads.runs.stream(..., event_handler=handler) has run. Also instantiating the handler and calling until_done() directly.
Common situations: Calling list(handler.text_deltas) to pre-collect output; refactoring away the with-block; misunderstandings about when the stream starts; sharing handler-created iterators across contexts.
Related errors
- A single event handler cannot be shared between multiple str
- No final run object found
- No run steps found
- No messages found
- Encountered a message delta with no previous snapshot
AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28).
Data as JSON: /api/errors/c8d0fd5368196af9.
Report an issue: GitHub.