moeru-ai/airi · error · Error
Gemini TTS request failed: ${response.status} ${await respon
Error message
Gemini TTS request failed: ${response.status} ${await response.text().catch(() => '')} What it means
Thrown by the Gemini TTS fetch wrapper when the Gemini API responds with a non-2xx status. The message includes the HTTP status and the raw response body (best-effort, empty on read failure). This is the upstream Google API rejecting the request — most often auth/quota/model issues. It fires only after the input/model body checks passed.
Source
Thrown at packages/stage-ui/src/libs/providers/providers/google-gemini-audio-speech/index.ts:99
if (!body.model)
throw new Error('Missing model for Gemini TTS')
const response = await globalThis.fetch(new URL(`models/${body.model}:generateContent`, baseUrl), {
method: 'POST',
headers: { 'x-goog-api-key': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify({
contents: [{ parts: [{ text: body.input }] }],
generationConfig: {
responseModalities: ['AUDIO'],
speechConfig: {
voiceConfig: { prebuiltVoiceConfig: { voiceName: body.voice || 'Kore' } },
},
...(body.temperature !== undefined ? { temperature: body.temperature } : {}),
},
}),
})
if (!response.ok)
throw new Error(`Gemini TTS request failed: ${response.status} ${await response.text().catch(() => '')}`)
const data = await response.json() as {
candidates?: Array<{ content?: { parts?: Array<{ inlineData?: { data?: string } }> } }>
}
const audio = data.candidates?.[0]?.content?.parts?.find(part => part.inlineData)?.inlineData?.data
if (!audio)
throw new Error('Gemini TTS response missing audio data')
return new Response(toWavFromPCM16(decodeBase64(audio), 24000), {
status: 200,
headers: { 'Content-Type': 'audio/wav' },
})
}
}
export const providerGoogleGeminiAudioSpeech = defineProvider<GoogleGeminiSpeechConfig>({
id: 'google-gemini-audio-speech',
name: 'Google Gemini',View on GitHub (pinned to 27111382b4)
Solutions
- Read the status and body in the message: 401/403 → fix the API key and ensure Gemini API is enabled; 429 → wait and retry with backoff; 404 → correct the model id; 400 → check the request shape.
- Confirm the API key in provider settings is valid and has access to the chosen TTS model.
- Verify the model id supports audio output (responseModalities: AUDIO).
- Enable billing / check quota in the Google Cloud console for sustained 429s.
Defensive patterns
Strategy: try-catch
Validate before calling
// before fetch, sanity-check the api key and model name
if (!apiKey) throw new Error('Gemini API key required')
if (!body.model) throw new Error('Gemini model required')
// network/quota errors are server-authoritative; catch at runtime Type guard
null
Try / catch
try {
const res = await provider.speech(model).fetch(url, { body: JSON.stringify(body) })
}
catch (err) {
if (err instanceof Error && err.message.startsWith('Gemini TTS request failed')) {
// parse status: 401/403 fix key; 429 back off; 404 fix model id; 400 fix request shape
}
else throw err
} Prevention
- Store a valid Gemini API key with Gemini API access enabled.
- Use a TTS-capable model id that supports AUDIO output.
- Enable billing and monitor quota to avoid sustained 429s.
When it happens
Trigger: globalThis.fetch to models/${model}:generateContent returns non-ok. Typical Google API errors: 400 (malformed request or unsupported model for TTS), 401/403 (invalid/missing API key or no access to the model), 429 (quota exceeded), 404 (model name wrong/unavailable).
Common situations: Wrong API key or key without Gemini API access. Quota/rate limit hit. Model id typo or a model that does not support AUDIO generation. Regional restriction. Billing not enabled on the Google Cloud project.
Related errors
- Gemini TTS response missing audio data
- Failed to fetch voices: ${response.statusText}
- listAccounts failed
- unlinkAccount failed
- HTTP ${res.status}: ${await readErrorDetail(res)}
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/bbf050b8028db98d.
Report an issue: GitHub.