{"record":{"id":"b1ea74e281b67f6c","repo":"conductor-oss/conductor","slug":"speech-api-call-failed","errorCode":null,"errorMessage":"Speech API call failed: ","messagePattern":"Speech API call failed: ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/openai/OpenAI.java","lineNumber":173,"sourceCode":"            String responseFormat =\n                    request.getResponseFormat() != null\n                            ? request.getResponseFormat().toLowerCase()\n                            : \"mp3\";\n\n            var speechRequest =\n                    new OpenAISpeechApi.SpeechRequest(\n                            request.getModel(),\n                            request.getText(),\n                            request.getVoice(),\n                            responseFormat,\n                            request.getSpeed());\n            byte[] audioData = speechApi.createSpeech(speechRequest);\n\n            List<Media> media = new ArrayList<>();\n            media.add(Media.builder().data(audioData).mimeType(\"audio/*\").build());\n            return LLMResponse.builder().media(media).build();\n        } catch (IOException e) {\n            throw new RuntimeException(\"Speech API call failed: \" + e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public VideoModel getVideoModel() {\n        return this.videoModel;\n    }\n\n    @Override\n    public LLMResponse generateVideo(VideoGenRequest request) {\n        VideoOptions options = getVideoOptions(request);\n        VideoPrompt videoPrompt = new VideoPrompt(request.getPrompt(), options);\n        VideoResponse response = videoModel.call(videoPrompt);\n\n        return LLMResponse.builder()\n                .jobId(response.getMetadata().getJobId())\n                .finishReason(response.getMetadata().getStatus())\n                .build();","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/openai/OpenAI.java#L155-L191","documentation":"OpenAI.java wraps an IOException from OpenAISpeechApi.createSpeech() in a RuntimeException with message \"Speech API call failed: \". This is the text-to-speech path (generateAudio), called when an AudioGenRequest is processed. The underlying IOException comes from the TTS API HTTP call failing (non-2xx or network error). The response is expected to be raw audio bytes, not JSON.","triggerScenarios":"generateAudio() is called with a TTS request (model, text, voice, format, speed) and the POST /v1/audio/speech request fails: invalid model (e.g. using a non-TTS model name), unsupported voice, 401 auth, 429 rate limit, or network error.","commonSituations":"Using a non-TTS model name (e.g. \"gpt-4o\" instead of \"tts-1\" or \"tts-1-hd\"); specifying a voice the model doesn't support; API key lacks TTS access; network timeout on long text input.","solutions":["Inspect getCause() — the IOException message contains the HTTP status and response body.","Verify the model is a TTS model (tts-1, tts-1-hd, gpt-4o-mini-tts).","Verify the voice is one OpenAI supports (alloy, echo, fable, onyx, nova, shimmer, or custom voices for gpt-4o-mini-tts).","Check responseFormat is a valid TTS format (mp3, opus, aac, flac, wav, pcm)."],"exampleFix":"// before\nAudioGenRequest req = new AudioGenRequest();\nreq.setModel(\"gpt-4o\"); // wrong — not a TTS model\n// after\nreq.setModel(\"tts-1-hd\");","handlingStrategy":"try-catch","validationCode":"// Validate TTS request before calling generateAudio()\nAudioGenRequest req = /* ... */;\nSet<String> ttsModels = Set.of(\"tts-1\", \"tts-1-hd\", \"gpt-4o-mini-tts\");\nif (!ttsModels.contains(req.getModel())) {\n    throw new IllegalArgumentException(\n        \"Model '\" + req.getModel() + \"' is not a TTS model. Use: \" + ttsModels);\n}\nif (req.getText() == null || req.getText().isBlank()) {\n    throw new IllegalArgumentException(\"Text is required for speech generation\");\n}\nSet<String> validVoices = Set.of(\"alloy\", \"echo\", \"fable\", \"onyx\", \"nova\", \"shimmer\");\nif (req.getVoice() != null && !validVoices.contains(req.getVoice())) {\n    log.warn(\"Voice '{}' is not a standard voice\", req.getVoice());\n}","typeGuard":"null","tryCatchPattern":"try {\n    LLMResponse audio = llm.generateAudio(request);\n} catch (RuntimeException e) {\n    Throwable cause = e.getCause();\n    if (cause instanceof IOException) {\n        log.error(\"TTS API failed: {}\", cause.getMessage());\n    }\n    throw e;\n}","preventionTips":["Validate the model is a TTS model (tts-1, tts-1-hd, gpt-4o-mini-tts) before calling.","Verify the voice is supported by the model.","Check responseFormat is a valid TTS format.","Handle long-text input by chunking to avoid timeouts."],"tags":["openai","text-to-speech","network","api-error","ai"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}