BerriAI/litellm · error · ValueError

Unexpected response type

Error message

Unexpected response type: {type(raw_response)}

What it means

LiteLLMResponsesTransformationHandler.transform_response only accepts raw_response values that are ResponsesAPIResponse instances — the typed object the Responses API client returns. Anything else (a plain dict, ModelResponse, string, or None) violates the transformation contract and is rejected before conversion to a chat completion. This is an internal API contract check, not user input validation.

Solutions

  1. Construct a ResponsesAPIResponse(**dict_payload) before calling transform_response
  2. Prefer the public litellm.completion path where typing is handled end to end
  3. Add an isinstance assert in custom adapters so wrong types fail loudly at the boundary
  4. Upgrade litellm if a provider adapter regression caused it

Example fix

// before
from litellm.types.llms.openai import ResponsesAPIResponse
model_response = transform_handler.transform_response(model, raw_response=data_dict, ...)  # ValueError: Unexpected response type

// after
raw = ResponsesAPIResponse(**data_dict)
model_response = transform_handler.transform_response(model, raw_response=raw, ...)
Defensive patterns

Strategy: type-guard

Validate before calling

from litellm.types.llms.openai import ResponsesAPIResponse

def ensure_responses_api_response(raw):
    if isinstance(raw, dict):
        return ResponsesAPIResponse(**raw)
    return raw

Type guard

from litellm.types.llms.openai import ResponsesAPIResponse

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

Try / catch

try:
    model_response = handler.transform_response(model, raw_response=raw, ...)
except ValueError as e:
    if "Unexpected response type" in str(e):
        raise TypeError(f"adapter must pass ResponsesAPIResponse, got {type(raw)}") from e
    raise

Prevention

When it happens

Trigger: Calling transform_response directly with a dict parsed from JSON instead of a ResponsesAPIResponse; a custom provider transformation returning the wrong type; version skew where a provider adapter changed its return type; middleware swapping the response object.

Common situations: Developers wiring custom providers into the responses bridge; code that re-implements parts of litellm's pipeline; partial upgrades where litellm subpackages disagree on types; tests passing fixtures of the wrong type.

Related errors


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

Appendix: source

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

        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 77b7c6c40c)