moeru-ai/airi · error · Error

Gemini TTS response missing audio data

Error message

Gemini TTS response missing audio data

What it means

The Gemini call succeeded at the HTTP level, but candidates[0].content.parts contains no part with inlineData — the model produced no audio bytes — so the provider refuses rather than returning a broken WAV. A 200 without audio usually means the response was blocked or the model answered in text instead of generating speech.

Solutions

  1. Log the full response JSON — promptFeedback and finishReason explain the empty audio
  2. Adjust the prompt text that triggers safety blocks
  3. Confirm the model actually supports audio output with responseModalities AUDIO
  4. Retry with the default voice 'Kore' to rule out an invalid voiceName

Example fix

// before
const data = await response.json()
const audio = data.candidates?.[0]?.content?.parts?.find(p => p.inlineData)?.inlineData?.data
if (!audio) throw new Error('Gemini TTS response missing audio data') // opaque

// after
const data = await response.json()
const reason = data.promptFeedback?.blockReason ?? data.candidates?.[0]?.finishReason
if (!audio) throw new Error(`Gemini returned no audio: ${reason ?? 'unknown reason'}`)
Defensive patterns

Strategy: fallback

Try / catch

try {
  await speak(text)
}
catch (err) {
  if (err.message.includes('missing audio data')) {
    // Retry once with sanitized text and the default voice before giving up.
    await speak(sanitize(text), { voice: 'Kore' })
  }
}

Prevention

When it happens

Trigger: Safety filters blocked the prompt (promptFeedback.blockReason or empty candidates); a finishReason like MAX_TOKENS or SAFETY cut generation; a model id that does not support the AUDIO response modality; an invalid voice name causing the API to return text only.

Common situations: Prompts with content the safety layer flags; the model swapped to a text-only variant while the voice config stayed; long input truncated before any audio part; regional model behavior differences.

Understand the failure class

Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/0ebfacef3ca406ea. Report an issue: GitHub.

Appendix: source

Thrown at packages/stage-ui/src/libs/providers/providers/google-gemini-audio-speech/index.ts:106

        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',
  nameLocalize: ({ t }) => t('settings.pages.providers.provider.google-gemini-audio-speech.title'),
  description: 'aistudio.google.com',
  descriptionLocalize: ({ t }) => t('settings.pages.providers.provider.google-gemini-audio-speech.description'),
  tasks: ['text-to-speech', 'tts'],
  icon: 'i-lobe-icons:gemini',
  iconColor: 'i-lobe-icons:gemini-color',
  createProviderConfig: () => googleGeminiSpeechConfigSchema,

View on GitHub (pinned to 677329427f)