moeru-ai/airi · error

Missing model for Gemini TTS

Error message

Missing model for Gemini TTS

What it means

The wrapper validates that the parsed request body includes a model identifier before forwarding to models/{model}:generateContent. Without a model the URL would be malformed and the Gemini request would fail; the library throws locally with a clear message instead.

Solutions

  1. Explicitly pass the TTS model (e.g. 'gemini-2.5-flash-preview-tts') in the speech request
  2. Set a default model in the provider configuration so callers need not pass one each time
  3. Check stored settings/config for an empty model value and restore a valid one
  4. Confirm the option key for model matches what the provider expects

Example fix

// before
await speech({ input: 'hello', model: undefined })
// after
await speech({ input: 'hello', model: 'gemini-2.5-flash-preview-tts' })
Defensive patterns

Strategy: validation

Validate before calling

const GEMINI_TTS_MODELS = ['gemini-2.5-flash-preview-tts', 'gemini-2.5-pro-preview-tts']
if (!model || !GEMINI_TTS_MODELS.includes(model)) throw new Error(`Invalid or missing Gemini TTS model: ${model}`)

Type guard

function hasModel(opts: { model?: string }): opts is { model: string } {
  return typeof opts.model === 'string' && opts.model.length > 0
}

Try / catch

try {
  const audio = await speech({ input, model })
} catch (e) {
  if (e instanceof Error && e.message.includes('Missing model')) {
    // set a default model and retry
  }
}

Prevention

When it happens

Trigger: Calling the speech API without specifying the TTS model, or with a model value of empty string/undefined, so body.model is falsy after JSON.parse.

Common situations: Provider configured without a default model, a settings migration dropped the stored model, or the caller passed the model under a wrong option key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-08). Data as JSON: /api/errors/f5a64b607336806d. Report an issue: GitHub.

Appendix: source

Thrown at packages/provider-inference/src/providers/cloud/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 438a067dde)