moeru-ai/airi · error
Missing input text for Gemini TTS
Error message
Missing input text for Gemini TTS
What it means
After parsing the JSON body, the Gemini TTS wrapper validates that the parsed body.input field contains text to synthesize. This error means the speech request reached the fetch wrapper with no input text. The library throws early instead of sending a doomed request to the Gemini API.
Solutions
- Pass non-empty text in the speech request options
- Trim and check the text before calling speech(); skip the call when empty
- If text comes from upstream (LLM, user input), guard that producer against empty output
- Verify the option key name matches the current provider API (renamed fields silently produce undefined)
Example fix
// before
await speech({ input: text })
// after
if (!text?.trim()) return
await speech({ input: text }) Defensive patterns
Strategy: validation
Validate before calling
const text = options.input?.trim()
if (!text) throw new Error('Refusing to call Gemini TTS with empty input text') Type guard
function hasInput(opts: { input?: string }): opts is { input: string } {
return typeof opts.input === 'string' && opts.input.trim().length > 0
} Try / catch
try {
const audio = await speech({ input: text, model })
} catch (e) {
if (e instanceof Error && e.message.includes('Missing input text')) {
// skip synthesis or prompt the user for text
}
} Prevention
- Trim and check text before every TTS call
- Guard upstream producers (LLM output, user input) against empty strings
- Log the request options before sending to catch silently-dropped fields
When it happens
Trigger: Invoking the speech API with an empty string or missing 'input'/'text' option, e.g. speech({ text: '' }) or a caller that computed the text to speak as undefined/empty.
Common situations: A pipeline upstream produced empty text (empty LLM output, stripped string), a UI sent the request before the user typed text, or the option was renamed in a refactor so the value lands in a different key.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- audio voices upstream returned malformed body
- Invalid accelerator: empty string
- Invalid request body
- Invalid request body
- Invalid request body
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-08).
Data as JSON: /api/errors/9ea83539e5310fe6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/provider-inference/src/providers/cloud/google-gemini-audio-speech/index.ts:80
const bytes = new Uint8Array(binary.length)
for (let index = 0; index < binary.length; index++)
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)View on GitHub (pinned to 438a067dde)