decolua/9router · error · Error
ElevenLabs TTS returned empty audio
Error message
ElevenLabs TTS returned empty audio
What it means
After a 200 response, ElevenLabs synthesize requires the audio body to be at least 1024 bytes before returning base64 MP3; anything smaller throws "ElevenLabs TTS returned empty audio". This catches responses that succeeded at the HTTP layer but contain no usable audio payload.
Source
Thrown at open-sse/handlers/ttsProviders/elevenlabs.js:45
let modelId = "eleven_flash_v2_5";
let voiceId = model;
if (model && model.includes("/")) [modelId, voiceId] = model.split("/");
const res = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
method: "POST",
headers: { "xi-api-key": credentials.apiKey, "Content-Type": "application/json" },
body: JSON.stringify({
text,
model_id: modelId,
voice_settings: { stability: 0.5, similarity_boost: 0.75 },
}),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(err?.detail?.message || `ElevenLabs TTS failed: ${res.status}`);
}
const buf = await res.arrayBuffer();
if (buf.byteLength < 1024) throw new Error("ElevenLabs TTS returned empty audio");
return { base64: Buffer.from(buf).toString("base64"), format: "mp3" };
},
};
View on GitHub (pinned to 90b52e06ff)
Solutions
- Check that the input text is non-empty after trimming before calling synthesize.
- Retry the request once — brief upstream truncation is usually transient.
- If the text is genuinely tiny (a single word), the <1KB threshold may false-positive; test the same text with a longer string to confirm, and consider treating the payload as valid.
- Check ElevenLabs status/your account quota; some degraded modes return empty audio with 200.
- Fall back to another TTS provider for the affected request.
Example fix
// before
await elevenlabs.synthesize(text, model, creds); // text may be ""
// after
const t = (text || "").trim();
if (!t) throw new Error("TTS text is empty");
await elevenlabs.synthesize(t, model, creds); Defensive patterns
Strategy: validation
Validate before calling
if (!text?.trim()) throw new Error("TTS text is empty");
if (text.trim().length < 1) throw new Error("TTS text too short to synthesize"); Type guard
function isSynthesizableText(t) {
return typeof t === "string" && t.trim().length > 0;
} Try / catch
try {
const audio = await elevenlabs.synthesize(text, model, creds);
} catch (e) {
if (e.message === "ElevenLabs TTS returned empty audio") {
// transient upstream issue — retry once, then fall back
try { return await elevenlabs.synthesize(text, model, creds); }
catch { return await fallbackTts(text); }
}
throw e;
} Prevention
- Reject empty/whitespace-only text before calling synthesize.
- Treat single occurrences as transient and retry once.
- Check ElevenLabs status/incidents if empty 200s cluster in time.
- Fall back to another provider so a single empty response does not fail the user request.
When it happens
Trigger: ElevenLabs returns 200 with a tiny body — usually an empty or near-empty response when the voice/model produced no audio, a truncated response on connection issues, or when the request contained empty/whitespace text so nothing was synthesized.
Common situations: Passing empty or whitespace-only text through the pipeline; extremely short text with certain voices producing sub-1KB payloads at low bitrates; ElevenLabs-side incidents returning empty 200s; chunked-response truncation through a proxy.
Related errors
- Bing TTS returned empty audio
- Upstream returned empty audio
- Gemini TTS returned no audio (finishReason: ${reason}, voice
- Invalid HuggingFace model ID
- Google TTS returned empty audio
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/9adaf09362f296e9.
Report an issue: GitHub.