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

  1. Pass non-empty text in the speech request options
  2. Trim and check the text before calling speech(); skip the call when empty
  3. If text comes from upstream (LLM, user input), guard that producer against empty output
  4. 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

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


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)