BerriAI/litellm · error · ValueError
Stream ended without a completed response
Error message
Stream ended without a completed response
What it means
The sync path of the responses bridge drains the stream iterator, then reads stream_iter.completed_response.response to rebuild the full response. If the stream ends without that attribute chain being populated (no completed_response object, or its .response is None), the bridge cannot produce a result and raises this ValueError. It means the stream terminated abnormally — often because the underlying provider stream raised or was closed early and the completion assembly never ran.
Source
Thrown at litellm/completion_extras/litellm_responses_transformation/handler.py:79
raise ValueError("Unexpected responses stream payload")
if hidden_params:
existing: Final = getattr(response, "_hidden_params", None)
if not isinstance(existing, dict) or not existing:
setattr(response, "_hidden_params", dict(hidden_params))
else:
for key, value in hidden_params.items():
existing.setdefault(key, value)
return response
def _collect_response_from_stream(self, stream_iter: Any) -> "ResponsesAPIResponse":
for _ in stream_iter:
pass
completed: Final = getattr(stream_iter, "completed_response", None)
response_obj: Final = getattr(completed, "response", None) if completed else None
if response_obj is None:
raise ValueError("Stream ended without a completed response")
hidden_params: Final = getattr(stream_iter, "_hidden_params", None)
response: Final = self._coerce_response_object(response_obj, hidden_params)
if not isinstance(response, ResponsesAPIResponse):
raise ValueError("Stream completed response is invalid")
return response
async def _collect_response_from_stream_async(self, stream_iter: Any) -> "ResponsesAPIResponse":
async for _ in stream_iter:
pass
completed: Final = getattr(stream_iter, "completed_response", None)
response_obj: Final = getattr(completed, "response", None) if completed else None
if response_obj is None:
raise ValueError("Stream ended without a completed response")
hidden_params: Final = getattr(stream_iter, "_hidden_params", None)
response: Final = self._coerce_response_object(response_obj, hidden_params)View on GitHub (pinned to 6c2dcb801b)
Solutions
- Check upstream logs/exceptions for the real cause — the stream usually failed before completion assembly
- Update litellm to pick up stream-completion fixes: pip install -U litellm
- If wrapping the stream iterator yourself, preserve completed_response (delegate getattr to the wrapped iterator)
Defensive patterns
Strategy: try-catch
Validate before calling
def stream_has_completed_response(stream_iter) -> bool:
return getattr(getattr(stream_iter, 'completed_response', None), 'response', None) is not None
# only meaningful after draining; guard collection:
# drained = list(stream_iter); assert stream_has_completed_response(stream_iter) Try / catch
try:
response = handler._collect_response_from_stream(stream)
except ValueError as e:
if 'Stream ended without a completed response' in str(e):
# stream died mid-way; safe to retry the whole request
response = retry_request()
else:
raise Prevention
- Retry the full request when a stream ends incomplete — partial state cannot be salvaged
- Set sane read timeouts so dead streams fail fast
- If wrapping stream iterators, forward completed_response via a property
When it happens
Trigger: Calling the responses-to-completion bridge synchronously on a stream that errors partway, is closed by the server, or comes from a transformation that never sets completed_response; also with mock/custom stream iterators lacking the attribute.
Common situations: Provider disconnects mid-stream; timeouts consuming the iterator; custom wrappers around the stream that drop the completed_response attribute; version mismatches in custom transformation code.
Related errors
- Unexpected responses stream payload
- Stream completed response is invalid
- tool call not supported: {tool_call}
- Error receiving chunk from stream: {e}
- Error receiving chunk from stream: {e}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/80f1b88460ca1adb.
Report an issue: GitHub.