BerriAI/litellm · error · ValueError

Stream completed response is invalid

Error message

Stream completed response is invalid

What it means

Raised by the sync stream-collection path of the chat-completions-to-Responses-API bridge. After the stream is fully drained, the handler reads stream_iter.completed_response.response, coerces it via _coerce_response_object, and requires the result to be a ResponsesAPIResponse. If coercion succeeds but the object still fails the isinstance check, the completed payload is malformed. In practice this is a defensive guard: it fires only on litellm internal bugs, version skew, or exotic custom stream wrappers.

Solutions

  1. Retry the same call with stream=False so the non-streaming bridge path is used, to confirm the model itself works
  2. Upgrade litellm to the latest patch release (bridge/stream-wrapper contract fixes land frequently)
  3. Inspect stream_iter.completed_response and its .response in a debugger right after iteration to see what object was accumulated
  4. If you pass a custom stream wrapper, ensure it sets completed_response.response to a ResponsesAPIResponse-shaped object before exhaustion
  5. File a litellm issue with the model, provider, and stream payload if it reproduces on the latest version

Example fix

// before
resp = bridge_handler.completion(**kwargs, stream=True)  # ValueError: Stream completed response is invalid

// after
resp = litellm.completion(model=model, messages=messages, stream=False)  # bypass stream collection while debugging
Defensive patterns

Strategy: try-catch

Type guard

from litellm.types.llms.openai import ResponsesAPIResponse

def has_valid_completed_response(stream_iter) -> bool:
    completed = getattr(stream_iter, "completed_response", None)
    resp = getattr(completed, "response", None) if completed else None
    return isinstance(resp, ResponsesAPIResponse) or isinstance(resp, dict)

Try / catch

try:
    resp = litellm.completion(model=m, messages=msgs, stream=True)
except ValueError as e:
    if "Stream completed response is invalid" in str(e):
        resp = litellm.completion(model=m, messages=msgs, stream=False)  # non-stream fallback
    else:
        raise

Prevention

When it happens

Trigger: litellm.completion(..., stream=True) on a model routed through the responses bridge where the CustomStreamWrapper finishes without a well-formed completed_response.response object (e.g. a custom_llm_provider stream wrapper, a cached_response stream, or a partially-accumulated completed object after early termination).

Common situations: Custom providers or proxies that return their own stream iterators without completed_response; mocked/fake streams in tests; mixing litellm versions where the wrapper no longer populates completed_response; debugging sessions that intercept the stream.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/9307e5b2380ea6c6. Report an issue: GitHub.

Appendix: source

Thrown at litellm/completion_extras/litellm_responses_transformation/handler.py:84

                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)
        if not isinstance(response, ResponsesAPIResponse):
            raise ValueError("Stream completed response is invalid")
        return response

    def validate_input_kwargs(self, kwargs: dict) -> ResponsesToCompletionBridgeHandlerInputKwargs:

View on GitHub (pinned to 77b7c6c40c)