{"record":{"id":"b9329f3077275f9a","repo":"BerriAI/litellm","slug":"error-in-response-object-format","errorCode":null,"errorMessage":"Error in response object format","messagePattern":"Error in response object format","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py","lineNumber":173,"sourceCode":"    response_object: dict | None = None,\n):\n    \"\"\"\n    Asynchronously converts a response object to a streaming response.\n\n    Args:\n        response_object (Optional[dict]): The response object to be converted. Defaults to None.\n\n    Raises:\n        Exception: If the response object is None.\n\n    Yields:\n        ModelResponse: The converted streaming response object.\n\n    Returns:\n        None\n    \"\"\"\n    if response_object is None:\n        raise Exception(\"Error in response object format\")\n\n    model_response_object: Final = ModelResponseStream()\n\n    if model_response_object is None:\n        raise Exception(\"Error in response creating model response object\")\n\n    choice_list: Final[list[StreamingChoices]] = []\n\n    if not response_object.get(\"choices\"):\n        from litellm.exceptions import APIError\n\n        raise APIError(\n            status_code=500,\n            message=(\n                f\"LiteLLM: provider returned a response with no 'choices'. Raw keys: {list(response_object.keys())}\"\n            ),\n            llm_provider=\"\",\n            model=\"\",","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/llm_response_utils/convert_dict_to_response.py#L155-L191","documentation":"convert_to_streaming_response (used for replaying cached responses as streams) raises this generic Exception when response_object is None. The function then goes on to build ModelResponseStream chunks from response_object['choices'], so a None input cannot be processed. It is a defensive precondition check at the top of the converter in convert_dict_to_response.py.","triggerScenarios":"Returning a cache hit with stream=True where the cached value deserializes to None; custom caching hooks (CustomLogger.async_get_cache) returning a falsy/malformed entry that gets forwarded as None; calling convert_to_streaming_response() with no arguments (the parameter defaults to None).","commonSituations":"Redis cache storing empty values or wrong keys; a custom cache implementation that returns None on miss but the caller treats it as a hit; corrupted cache entries after a serialization format change between litellm versions.","solutions":["Make your custom cache hook return None on miss and only yield cached values that are valid completion dicts.","Validate/repair cached entries: ensure the stored JSON has 'choices' before treating it as a cache hit.","Flush stale cache entries after upgrading litellm if the cached payload format changed.","If calling the converter directly, always pass a populated response_object dict."],"exampleFix":"// before (custom logger cache hook)\ncached = await self.async_get_cache(**kwargs)\nreturn cached  # may be None\n\n# after\ncached = await self.async_get_cache(**kwargs)\nreturn cached if isinstance(cached, dict) and cached.get('choices') else None","handlingStrategy":"validation","validationCode":"def is_replayable_cache_hit(cached) -> bool:\n    return isinstance(cached, dict) and bool(cached.get('choices'))","typeGuard":null,"tryCatchPattern":"try:\n    for chunk in convert_to_streaming_response(response_object=cached):\n        yield chunk\nexcept Exception as e:\n    if 'response object format' in str(e):\n        cache.delete(key); yield from real_stream()  # bypass cache\n    else:\n        raise","preventionTips":["Custom cache hooks must return None on miss; never forward None as a hit.","Validate cached dicts have 'choices' before replaying them as streams.","Flush cache after litellm upgrades that change stored payload formats."],"tags":["streaming","caching","response-conversion"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}