{"record":{"id":"9c38fcd69e136dbb","repo":"conductor-oss/conductor","slug":"gemini-generateaudio-failed","errorCode":null,"errorMessage":"Gemini generateAudio failed","messagePattern":"Gemini generateAudio failed","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/gemini/GeminiVertex.java","lineNumber":251,"sourceCode":"                    if (c.content() == null || c.content().parts() == null) continue;\n                    for (GeminiApi.Part p : c.content().parts()) {\n                        if (p.inlineData() != null && p.inlineData().data() != null) {\n                            byte[] bytes =\n                                    java.util.Base64.getDecoder().decode(p.inlineData().data());\n                            media.add(\n                                    Media.builder()\n                                            .data(bytes)\n                                            .mimeType(\"audio/\" + request.getResponseFormat())\n                                            .build());\n                        }\n                    }\n                }\n            }\n            return LLMResponse.builder().media(media).build();\n        } catch (RuntimeException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new RuntimeException(\"Gemini generateAudio failed\", e);\n        }\n    }\n}\n","sourceCodeStart":233,"sourceCodeEnd":255,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/gemini/GeminiVertex.java#L233-L255","documentation":"GeminiVertex.generateAudio() catches any checked Exception (not RuntimeException) during the TTS audio generation flow — which includes the generateContent call with AUDIO response modality and the Base64 decode of returned audio data — and wraps it with this message. The original exception is preserved as the cause. RuntimeExceptions (like a failed Base64 decode from java.util.Base64 which throws IllegalArgumentException, a RuntimeException) propagate unchanged via the first catch.","triggerScenarios":"IOException from the generateContent HTTP call with responseModalities=[AUDIO], or a checked exception during response parsing. This fires when the Gemini API call for TTS fails at the transport layer or the response cannot be processed.","commonSituations":"Model doesn't support audio output (e.g. using a non-TTS model name). Invalid voice name in PrebuiltVoiceConfig. API key lacks TTS permissions. Network failure to the Gemini endpoint. API version mismatch where the speechConfig field is not recognised.","solutions":["Inspect getCause() for the specific checked exception detail.","Verify the model supports audio output (e.g. 'gemini-2.5-flash-preview-tts' or a model with TTS capability).","Verify the voice name is one of Google's prebuilt voices (Charon, Fenrir, Aoede, etc.).","Check the API key / Vertex AI credentials have access to TTS models.","Verify network connectivity to the Gemini endpoint."],"exampleFix":"// before\nString model = \"gemini-2.5-flash\"; // no TTS support\nAudioGenRequest req = AudioGenRequest.builder().model(model).voice(\"Unknown\").build();\n\n// after\nString model = \"gemini-2.5-flash-preview-tts\";\nAudioGenRequest req = AudioGenRequest.builder().model(model).voice(\"Charon\").build();","handlingStrategy":"try-catch","validationCode":"// Validate TTS request before calling\nprivate static final Set<String> GEMINI_TTS_MODELS =\n    Set.of(\"gemini-2.5-flash-preview-tts\", \"gemini-2.5-pro-preview-tts\");\nprivate static final Set<String> VALID_VOICES =\n    Set.of(\"Charon\", \"Fenrir\", \"Aoede\", \"Leda\", \"Orus\", \"Puck\", \"Zephyr\");\n\nvoid validateAudioRequest(AudioGenRequest req) {\n    if (!GEMINI_TTS_MODELS.contains(req.getModel())) {\n        throw new IllegalArgumentException(\n            \"Use a TTS-capable model (gemini-2.5-flash-preview-tts). Got: \" + req.getModel());\n    }\n    if (req.getVoice() != null && !VALID_VOICES.contains(req.getVoice())) {\n        throw new IllegalArgumentException(\n            \"Invalid voice. Valid: \" + VALID_VOICES);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return vertex.generateAudio(request);\n} catch (RuntimeException e) {\n    if (e.getMessage().equals(\"Gemini generateAudio failed\")) {\n        throw new RuntimeException(\n            \"Gemini audio generation failed — verify TTS model name and voice. \"\n            + \"Cause: \" + e.getCause().getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Use a TTS-specific model name (gemini-2.5-flash-preview-tts) — regular chat models don't output audio.","Verify the voice name is one of Google's prebuilt voices.","Confirm the API key / Vertex AI credentials have TTS model access.","Log the cause exception to distinguish model errors from network failures."],"tags":["gemini","audio","tts","network","io"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}