BerriAI/litellm · error · ValueError

Unexpected response type: {type(raw_response)}

Error message

Unexpected response type: {type(raw_response)}

What it means

transform_response raises this when the object passed as raw_response is not a litellm ResponsesAPIResponse. This method is the Responses→chat-completions converter used by the bridge; feeding it a raw httpx.Response, a plain dict, or an OpenAI SDK response object instead of the parsed ResponsesAPIResponse trips this guard.

Source

Thrown at litellm/completion_extras/litellm_responses_transformation/transformation.py:742

        self,
        model: str,
        raw_response: "BaseModel",
        model_response: "ModelResponse",
        logging_obj: "LiteLLMLoggingObj",
        request_data: dict,
        messages: list["AllMessageValues"],
        optional_params: dict,
        litellm_params: dict,
        encoding: object,
        api_key: str | None = None,
        json_mode: bool | None = None,
    ) -> "ModelResponse":
        """Transform Responses API response to chat completion response"""
        from litellm.responses.utils import ResponseAPILoggingUtils
        from litellm.types.llms.openai import ResponsesAPIResponse

        if not isinstance(raw_response, ResponsesAPIResponse):
            raise ValueError(f"Unexpected response type: {type(raw_response)}")

        if raw_response.error is not None:
            raise ValueError(f"Error in response: {raw_response.error}")

        output_items = raw_response.output
        if len(output_items) == 0:
            recovered_output_items: Final = self._recover_output_items_from_logging(logging_obj)
            if recovered_output_items:
                output_items = cast(Any, recovered_output_items)
                raw_response.output = cast(Any, recovered_output_items)
                verbose_logger.warning(
                    "Recovered empty Responses API output from raw SSE for model=%s",
                    model,
                )

        # Convert response output to choices using the static helper
        choices: Final = self._convert_response_output_to_choices(
            output_items=output_items,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Parse the payload first: ResponsesAPIResponse(**json_body) before calling transform_response
  2. Let litellm's own provider adapter do the parsing — do not call transform_response with transport-level objects
  3. In tests, construct fixtures as ResponsesAPIResponse instances or validated dicts

Example fix

# before
resp = await client.post(url, json=payload)
model_resp = handler.transform_response(resp.json(), ...)  # raw dict

# after
from litellm.types.llms.openai import ResponsesAPIResponse
parsed = ResponsesAPIResponse(**resp.json())
model_resp = handler.transform_response(parsed, ...)
Defensive patterns

Strategy: type-guard

Validate before calling

from litellm.types.llms.openai import ResponsesAPIResponse

def is_parsed_responses_payload(raw) -> bool:
    return isinstance(raw, ResponsesAPIResponse)

Type guard

from litellm.types.llms.openai import ResponsesAPIResponse

def is_responses_api_response(v) -> bool:
    return isinstance(v, ResponsesAPIResponse)

Prevention

When it happens

Trigger: Calling LiteLLMResponsesTransformationHandler.transform_response (or the bridge) with the unparsed HTTP body or an SDK object; a provider adapter returning the raw JSON dict instead of validating it into ResponsesAPIResponse first.

Common situations: Custom provider integrations that skip the schema validation step; tests passing fixtures as dicts; refactors that changed what the transport returns.

Related errors


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