decolua/9router · error · Error
Google TTS returned empty audio
Error message
Google TTS returned empty audio
What it means
A 200 response from batchexecute is parsed line-wise: `data.split("\n")[3]` → JSON → `[0][2]` → JSON → first element must be a base64 string of at least 100 chars. If the audio payload is missing, empty, or suspiciously short, this error is thrown. It means Google responded OK but without usable audio.
Source
Thrown at open-sse/handlers/ttsProviders/googleTts.js:51
bl: token.bl,
hl: lang,
"soc-app": 1, "soc-platform": 1, "soc-device": 1,
_reqid: reqId,
rt: "c",
});
const payload = [cleanText, lang, null, "undefined", [0]];
const body = new URLSearchParams();
body.append("f.req", JSON.stringify([[[rpcId, JSON.stringify(payload), null, "generic"]]]));
const res = await fetch(`https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?${query}`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded", "Referer": "https://translate.google.com/" },
body: body.toString(),
});
if (!res.ok) throw new Error(`Google TTS failed: ${res.status}`);
const data = await res.text();
const split = JSON.parse(data.split("\n")[3]);
const base64 = JSON.parse(split[0][2])[0];
if (!base64 || base64.length < 100) throw new Error("Google TTS returned empty audio");
return { base64, format: "mp3" };
},
};
View on GitHub (pinned to 90b52e06ff)
Solutions
- Validate `text` is non-empty before calling synthesize and keep it under the length limit (chunk long text)
- Log the raw response to check whether line 3 / [0][2] still holds the audio array; update the parse indices if the layout changed
- Check the in-body status/error inside the parsed split payload — batchexecute often reports errors with HTTP 200
- Fall back to another TTS provider (the handler layer supports per-provider fallback)
Example fix
// before
if (!base64 || base64.length < 100) throw new Error('Google TTS returned empty audio');
// after
if (!base64 || base64.length < 100) {
throw new Error('Google TTS returned empty audio; raw=' + data.slice(0, 300));
} Defensive patterns
Strategy: validation
Validate before calling
if (!text?.trim()) throw new Error('text required for Google TTS');
if (text.length > 200) text = text.slice(0, 200); // or chunk Type guard
const parsed = JSON.parse(data.split('\n')[3]); const okShape = Array.isArray(parsed?.[0]?.[2]) && JSON.parse(parsed[0][2])?.[0]?.length >= 100; Try / catch
try { return await googleTts.synthesize(text); } catch (e) { if (e.message === 'Google TTS returned empty audio') return fallbackProvider(text); throw e; } Prevention
- Never pass empty/whitespace text; validate at the API boundary
- Wrap JSON.parse in try/catch and log raw responses to catch layout changes
- Keep a non-scraping TTS provider as fallback
When it happens
Trigger: The RPC returns an in-body error envelope (e.g. unknown text encoding, unsupported language, empty text) rather than audio; the batchexecute response layout changed so index [3]/[0][2] now points at the wrong chunk.
Common situations: Empty or whitespace-only text passed to synthesize; very long text exceeding the RPC limit; Google changing the batchexecute response line format (breaking the fixed index parse).
Related errors
- Failed to parse Google token
- Upstream returned empty audio
- Bing TTS returned empty audio
- ElevenLabs TTS returned empty audio
- Gemini TTS returned no audio (finishReason: ${reason}, voice
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/a20cfb844e109751.
Report an issue: GitHub.