moeru-ai/airi · error · Error
Missing model for Gemini TTS
Error message
Missing model for Gemini TTS
What it means
Thrown inside the Gemini TTS custom fetch wrapper when the parsed request body has no `model` field. The wrapper interpolates body.model into the Gemini models/${model}:generateContent path, so an absent model would produce a malformed URL. The guard fails fast before the request is built.
Source
Thrown at packages/stage-ui/src/libs/providers/providers/google-gemini-audio-speech/index.ts:82
bytes[index] = binary.charCodeAt(index)
return bytes
}
function createAudioFetch(apiKey: string, baseUrl: string) {
return async (_input: RequestInfo | URL, init?: RequestInit) => {
if (!init?.body || typeof init.body !== 'string')
throw new Error('Invalid request body')
const body = JSON.parse(init.body) as {
input?: string
model?: string
voice?: string
temperature?: number
}
if (!body.input)
throw new Error('Missing input text for Gemini TTS')
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(() => '')}`)
View on GitHub (pinned to 27111382b4)
Solutions
- Select a Gemini TTS model in the provider settings before invoking synthesis.
- Pass a non-empty `model` in the request body JSON.
- Default the model in the caller if the user left it blank, before calling fetch.
Example fix
// before
fetch(url, { body: JSON.stringify({ input: 'Hello', voice: 'Kore' }) })
// after
fetch(url, { body: JSON.stringify({ input: 'Hello', model: 'gemini-2.5-flash-preview-tts', voice: 'Kore' }) }) Defensive patterns
Strategy: validation
Validate before calling
function hasGeminiModel(body: unknown): boolean {
return !!body && typeof body === 'object'
&& typeof (body as { model?: unknown }).model === 'string'
&& (body as { model: string }).model.length > 0
} Type guard
function isGeminiTtsBody(body: unknown): body is { input: string, model: string, voice?: string } {
return !!body && typeof body === 'object'
&& typeof (body as { model?: unknown }).model === 'string'
&& (body as { model: string }).model.length > 0
} Try / catch
try {
await provider.speech(model).fetch(url, { body: JSON.stringify(body) })
}
catch (err) {
if (err instanceof Error && err.message === 'Missing model for Gemini TTS') {
// caller must set a Gemini TTS model id in the body
}
else throw err
} Prevention
- Select a Gemini TTS model in provider settings before invoking synthesis.
- Default the model in the caller if the user left it blank.
- Use the exact `model` key in the request body.
When it happens
Trigger: Calling the provider's speech fetch with a JSON string body whose `model` key is missing or undefined. The caller did not select a Gemini TTS model (e.g. gemini-2.5-flash-preview-tts) before invoking synthesis.
Common situations: Provider settings have no model selected. Caller bug omitting the model field. Config reset cleared the model selection.
Related errors
- Missing input text for Gemini TTS
- Vision provider/model not configured
- Aliyun NLS credentials are incomplete.
- Replicate provider is not configured. Missing API Key.
- Gemini TTS request failed: ${response.status} ${await respon
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/2a16e33d5a8445af.
Report an issue: GitHub.