{"record":{"id":"ed3c997f401b0048","repo":"decolua/9router","slug":"minimax-tts-returned-no-audio","errorCode":null,"errorMessage":"MiniMax TTS returned no audio","messagePattern":"MiniMax TTS returned no audio","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/handlers/ttsProviders/minimax.js","lineNumber":5,"sourceCode":"import { Buffer } from \"node:buffer\";\n\nfunction hexToBase64(audioHex) {\n  const clean = typeof audioHex === \"string\" ? audioHex.trim() : \"\";\n  if (!clean) throw new Error(\"MiniMax TTS returned no audio\");\n  if (clean.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(clean)) {\n    throw new Error(\"MiniMax TTS returned invalid audio\");\n  }\n  return Buffer.from(clean, \"hex\").toString(\"base64\");\n}\n\n// MiniMax T2A HTTP: returns hex-encoded audio in non-streaming mode.\nexport default async function minimaxTts({ baseUrl, apiKey, text, modelId, voiceId }) {\n  const res = await fetch(baseUrl, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\", \"Authorization\": `Bearer ${apiKey}` },\n    body: JSON.stringify({\n      model: modelId || \"speech-2.8-hd\",\n      text,\n      stream: false,\n      language_boost: \"auto\",\n      output_format: \"hex\",\n      voice_setting: {","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/ttsProviders/minimax.js#L1-L23","documentation":"MiniMax's non-streaming T2A API returns audio as a hex-encoded string. `hexToBase64` converts it to base64 and throws this error when the hex string is empty/absent (after trim). It fires when the upstream response contains no `audio_hex`/`data.audio` value at all.","triggerScenarios":"MiniMax responds 200 with `base_resp.status_code === 0` but no audio hex field — e.g. empty text input, voice/model mismatch, or a response shape where the audio key is absent.","commonSituations":"Empty or whitespace-only text passed through; wrong modelId/voiceId combo yielding silent success; MiniMax changing the response field name; streaming vs non-streaming mode confusion (stream mode returns chunks, not hex).","solutions":["Log the full parsed response to see which field (if any) holds audio and whether an in-body error message exists","Ensure `text` is non-empty and the model/voice IDs are valid for MiniMax T2A","Confirm you are in non-streaming mode — hex audio is only returned there; handle streaming chunks separately","Check `base_resp.status_code` even on 200; a nonzero code means the audio key is legitimately absent"],"exampleFix":"// before\nconst hex = data.data?.audio;\nconst b64 = hexToBase64(hex); // throws 'no audio' if undefined\n// after\nif (data.base_resp?.status_code !== 0) throw new Error(data.base_resp?.status_msg);\nconst b64 = hexToBase64(data.data?.audio);","handlingStrategy":"type-guard","validationCode":"if (!text?.trim()) throw new Error('text required for MiniMax TTS');\nif (data.base_resp?.status_code !== 0) throw new Error(data.base_resp?.status_msg || 'MiniMax upstream error');","typeGuard":"const isHexAudio = (v) => typeof v === 'string' && v.trim().length > 0 && v.trim().length % 2 === 0 && /^[0-9a-f]+$/i.test(v.trim());","tryCatchPattern":"try { return await minimaxTts(...); } catch (e) { if (e.message === 'MiniMax TTS returned no audio') { logger.error('minimax empty audio', { status: data?.base_resp }); return fallbackTts(text); } throw e; }","preventionTips":["Check base_resp.status_code on every MiniMax response, even 200s","Use non-streaming mode when relying on hex audio extraction","Validate text and model/voice IDs before the call"],"tags":["tts","minimax","empty-response","hex"],"backgroundTag":"empty-response-body","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}