{"record":{"id":"f1d7367d72ef2fff","repo":"BerriAI/litellm","slug":"no-audio-part-found-in-the-response","errorCode":null,"errorMessage":"No audio part found in the response","messagePattern":"No audio part found in the response","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/endpoints/speech/speech_to_completion_bridge/transformation.py","lineNumber":108,"sourceCode":"        )\n\n        return wav_header + pcm_data\n\n    def _is_gemini_tts_model(self, model: str) -> bool:\n        \"\"\"Check if the model is a Gemini TTS model that returns PCM16 data.\"\"\"\n        return \"gemini\" in model.lower() and (\"tts\" in model.lower() or \"preview-tts\" in model.lower())\n\n    def transform_response(self, model_response: \"ModelResponse\") -> \"HttpxBinaryResponseContent\":\n        import base64\n\n        import httpx\n\n        from litellm.types.llms.openai import HttpxBinaryResponseContent\n        from litellm.types.utils import Choices\n\n        audio_part: Final = cast(Choices, model_response.choices[0]).message.audio\n        if audio_part is None:\n            raise ValueError(\"No audio part found in the response\")\n        audio_content: Final = audio_part.data\n\n        # Decode base64 to get binary content\n        binary_data = base64.b64decode(audio_content)\n\n        # Check if this is a Gemini TTS model that returns raw PCM16 data\n        model: Final = getattr(model_response, \"model\", \"\")\n        headers: Final = {}\n        if self._is_gemini_tts_model(model):\n            # Convert PCM16 to WAV format for proper audio file playback\n            binary_data = self._convert_pcm16_to_wav(binary_data)\n            headers[\"Content-Type\"] = \"audio/wav\"\n        else:\n            headers[\"Content-Type\"] = \"audio/mpeg\"\n\n        # Create an httpx.Response object\n        response: Final = httpx.Response(status_code=200, content=binary_data, headers=headers)\n        return HttpxBinaryResponseContent(response)","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/endpoints/speech/speech_to_completion_bridge/transformation.py#L90-L126","documentation":"Raised by SpeechToCompletionBridgeTransformationHandler.transform_response (transformation.py:108) when the ModelResponse's first choice has message.audio set to None. The bridge works by asking a chat model for audio output; if the provider returns text-only content (no audio part), there is nothing to decode into HttpxBinaryResponseContent and the call fails.","triggerScenarios":"Using a chat model that does not support audio output (e.g. plain gpt-4o instead of gpt-4o-audio-preview); omitting modalities/audio request parameters so the provider returns a text answer; the provider ignoring the audio request; an error/empty choice shape from the provider.","commonSituations":"Pointing the speech bridge at a non-audio-capable model; missing or stripped audio-related optional_params (e.g. audio voice/format) in the transformed request; provider-side changes where audio responses are gated behind specific parameters; model_response.choices being empty (this raises IndexError instead — a sibling failure).","solutions":["Use an audio-capable chat model such as 'gpt-4o-audio-preview' or a Gemini TTS model","Verify the request includes the audio parameters the bridge sets (e.g. audio={'voice': ..., 'format': 'wav'}) and that custom optional_params do not override them","Inspect the raw completion response (message.content) to see what the model actually returned — often a text refusal or answer indicating audio was not generated","If you need plain TTS, call the provider's TTS API directly (e.g. openai TTS) instead of the chat-completion bridge"],"exampleFix":"# before\nresp = litellm.audio_speech(model=\"gpt-4o\", input=\"hello\", voice=\"alloy\")  # no audio output\n\n# after\nresp = litellm.audio_speech(model=\"gpt-4o-audio-preview\", input=\"hello\", voice=\"alloy\")","handlingStrategy":"type-guard","validationCode":"AUDIO_CHAT_MODELS = {\"gpt-4o-audio-preview\", \"gpt-4o-mini-audio-preview\"}\n\ndef supports_audio_output(model: str) -> bool:\n    m = model.split(\"/\")[-1].lower()\n    return m in AUDIO_CHAT_MODELS or \"tts\" in m  # gemini tts models\n\nif not supports_audio_output(model):\n    raise ValueError(f\"{model} cannot return audio; use gpt-4o-audio-preview or a Gemini TTS model\")","typeGuard":"def response_has_audio(model_response) -> bool:\n    try:\n        return model_response.choices[0].message.audio is not None\n    except (IndexError, AttributeError):\n        return False","tryCatchPattern":"try:\n    audio = litellm.audio_speech(model=model, input=text, voice=voice)\nexcept ValueError as e:\n    if \"No audio part found\" in str(e):\n        # model returned text-only; retry with an audio-capable model\n        audio = litellm.audio_speech(model=\"gpt-4o-audio-preview\", input=text, voice=voice)","preventionTips":["Restrict speech-bridge calls to audio-capable models (gpt-4o-audio-preview, gemini TTS variants)","Do not override the audio request params the bridge injects","Log the raw completion response when debugging missing audio parts"],"tags":["tts","speech","audio","model-capability","response-parsing"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}