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

  1. Check upstream logs/exceptions for the real cause — the stream usually failed before completion assembly
  2. Update litellm to pick up stream-completion fixes: pip install -U litellm
  3. 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

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


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/80f1b88460ca1adb. Report an issue: GitHub.