{"record":{"id":"b8a5b93ece6ea68e","repo":"BerriAI/litellm","slug":"invalid-completion-response-no-choices-found","errorCode":null,"errorMessage":"Invalid completion response: no choices found","messagePattern":"Invalid completion response: no choices found","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/google_genai/adapters/transformation.py","lineNumber":493,"sourceCode":"\n    def translate_completion_to_generate_content(\n        self,\n        response: ModelResponse,\n    ) -> dict[str, object]:\n        \"\"\"\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\"},","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/google_genai/adapters/transformation.py#L475-L511","documentation":"When converting a litellm completion ModelResponse back into Google GenAI generate_content format, the translator reads response.choices[0]. An empty choices list (falsy) means there is no candidate to transform — the Google API always returns candidates, so the adapter aborts with ValueError rather than emitting a malformed response.","triggerScenarios":"The underlying completion returned a ModelResponse with choices=[] — possible with some providers on content-filtered/empty completions, error-ish success responses, or middleware (hooks, fallback logic) that strips choices before the transform runs.","commonSituations":"Safety filters causing providers to return empty candidates; router post-call hooks mutating the response; LiteLLM mock/fake-stream paths that build ModelResponse without choices.","solutions":["Log the raw completion response before the adapter transforms it to confirm choices is empty and why","Retry without the response-mutating hook/fallback layer to see if choices survive","Adjust request params (e.g. safety settings, max output tokens) so the provider returns at least one candidate","Handle the ValueError in your caller and surface a domain-specific 'no candidates' error to the user"],"exampleFix":"# before\nr = generate_content(model=m, contents=c)  # raises when provider returns empty choices\n\n# after\nbase = litellm.completion(model='gemini/'+m, messages=msgs)\nif not base.choices:\n    raise RuntimeError('provider returned no candidates')\nr = generate_content(model=m, contents=c)","handlingStrategy":"validation","validationCode":"base = litellm.completion(model='gemini/' + model, messages=msgs)\nif not getattr(base, \"choices\", None):\n    raise RuntimeError(\"provider returned zero candidates; adjust safety/token params\")","typeGuard":"def has_choices(resp) -> bool:\n    return bool(getattr(resp, \"choices\", None))","tryCatchPattern":"try:\n    r = generate_content(model=m, contents=c)\nexcept ValueError as e:\n    if \"no choices found\" in str(e):\n        retry_with_relaxed_safety_settings(m, c)","preventionTips":["Watch for response-mutating hooks that drop choices","Treat empty candidates as a retryable provider condition"],"tags":["google-genai","response-validation","adapter"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}