{"record":{"id":"e3464b5af79e634f","repo":"BerriAI/litellm","slug":"invalid-completion-response-no-message-found-in-c","errorCode":null,"errorMessage":"Invalid completion response: no message found in choice","messagePattern":"Invalid completion response: no message found in choice","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/google_genai/adapters/transformation.py","lineNumber":498,"sourceCode":"        \"\"\"\n        Transform litellm completion response to Google GenAI generate_content format\n\n        Args:\n            response: ModelResponse from litellm.completion\n\n        Returns:\n            Dict in Google GenAI generate_content response format\n        \"\"\"\n\n        # Extract the main response content\n        choice: Final = response.choices[0] if response.choices else None\n        if not choice:\n            raise ValueError(\"Invalid completion response: no choices found\")\n\n        # Handle different choice types (Choices vs StreamingChoices)\n        if isinstance(choice, Choices):\n            if not choice.message:\n                raise ValueError(\"Invalid completion response: no message found in choice\")\n            parts = self._transform_openai_message_to_google_genai_parts(choice.message)\n        else:\n            # Fallback for generic choice objects\n            message_content = getattr(choice, \"message\", {}).get(\"content\", \"\") or getattr(choice, \"delta\", {}).get(\n                \"content\", \"\"\n            )\n            parts = [{\"text\": message_content}] if message_content else []\n\n        # Create Google GenAI format response\n        generate_content_response: Final[dict[str, object]] = {\n            \"candidates\": [\n                {\n                    \"content\": {\"parts\": parts, \"role\": \"model\"},\n                    \"finishReason\": self._map_finish_reason(getattr(choice, \"finish_reason\", None)),\n                    \"index\": 0,\n                    \"safetyRatings\": [],\n                }\n            ],","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/google_genai/adapters/transformation.py#L480-L516","documentation":"Deeper validation in the same transform: the first choice exists and is a Choices (non-streaming) instance, but choice.message is falsy. Without a message there is no content to build Google GenAI parts from, so translation stops with ValueError.","triggerScenarios":"A completion response whose choice carries only tool_calls or an empty message object with no content and no role data the parts-transformer can use; or custom response classes from hooks/mocks where message was never populated.","commonSituations":"Tool-call-only responses flowing through the generate_content adapter; response-scrubbing hooks; fake/mock ModelResponse objects built in tests without a message.","solutions":["Inspect the raw choice: print(choice) before transform to see whether message is empty and why","If you control construction (tests/mocks), always populate Choices(message=Messages(content=...))","For tool-call flows, translate tool_calls to Google functionCall parts before calling the adapter, or use litellm.completion directly","Update litellm if a newer version maps tool-call-only choices into parts"],"exampleFix":"# before (test mock)\nresp = ModelResponse(choices=[Choices()])  # message missing -> ValueError\n\n# after\nfrom litellm.types.utils import Choices, Message\nresp = ModelResponse(choices=[Choices(message=Message(content='ok'))])","handlingStrategy":"validation","validationCode":"choice = base.choices[0] if base.choices else None\nif choice is not None and not getattr(choice, \"message\", None):\n    raise RuntimeError(\"choice has no message (tool-call-only?); translate parts first\")","typeGuard":"def choice_has_message(choice) -> bool:\n    return bool(getattr(choice, \"message\", None))","tryCatchPattern":"try:\n    r = generate_content(model=m, contents=c)\nexcept ValueError as e:\n    if \"no message found\" in str(e):\n        handle_tool_call_only_response(base)","preventionTips":["Always populate Messages in mocks/tests","Convert tool-call-only responses before adapter transforms"],"tags":["google-genai","response-validation","adapter","tool-calls"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}