HeyPuter/puter · error · HttpError
field_invalid
field_invalid
Error message
Invalid model: ${model}. Expected: ${GEMINI_TTS_MODELS.map(({ id }) => id).join(', ')} What it means
GeminiTTSProvider.synthesize resolves model (defaulting to gemini-2.5-flash-preview-tts) and checks it against GEMINI_TTS_MODELS. If the id is not found, it throws HTTP 400 (legacyCode field_invalid) with fields.key='model', fields.expected (the supported ids), and fields.got.
Source
Thrown at src/backend/drivers/ai-tts/providers/gemini/GeminiTTSProvider.ts:154
model: modelArg,
instructions,
test_mode,
} = args;
if (test_mode) {
return { url: SAMPLE_AUDIO_URL, content_type: 'audio' };
}
if (typeof text !== 'string' || !text.trim()) {
throw new HttpError(400, 'Missing required field: text', {
legacyCode: 'field_required',
fields: { key: 'text' },
});
}
const model = modelArg || DEFAULT_MODEL;
if (!GEMINI_TTS_MODELS.find(({ id }) => id === model)) {
throw new HttpError(
400,
`Invalid model: ${model}. Expected: ${GEMINI_TTS_MODELS.map(({ id }) => id).join(', ')}`,
{
legacyCode: 'field_invalid',
fields: {
key: 'model',
expected: GEMINI_TTS_MODELS.map(({ id }) => id).join(
', ',
),
got: model,
},
},
);
}
const voice = voiceArg || DEFAULT_VOICE;
if (
!GEMINI_TTS_VOICES.find(View on GitHub (pinned to 908ec23eda)
Solutions
- Use a GEMINI_TTS_MODELS id: gemini-2.5-flash-preview-tts, gemini-2.5-pro-preview-tts, gemini-3.1-flash-tts-preview (read fields.expected).
- Omit model to accept the default (gemini-2.5-flash-preview-tts).
- Call list_engines({ provider: 'gemini' }) to fetch supported ids.
Example fix
// before
await driver.synthesize({ text: 'hi', provider: 'gemini', model: 'gemini-1.5-flash' });
// after
await driver.synthesize({ text: 'hi', provider: 'gemini', 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', 'gemini-3.1-flash-tts-preview'];
function synthesizeGemini(text, model = 'gemini-2.5-flash-preview-tts') {
if (!GEMINI_TTS_MODELS.includes(model)) {
throw new Error(`Unsupported Gemini TTS model: ${model}. Use one of: ${GEMINI_TTS_MODELS.join(', ')}`);
}
return driver.synthesize({ text, provider: 'gemini', model });
} Type guard
const GEMINI_TTS_MODELS = ['gemini-2.5-flash-preview-tts', 'gemini-2.5-pro-preview-tts', 'gemini-3.1-flash-tts-preview'] as const; type GeminiTTSModel = typeof GEMINI_TTS_MODELS[number]; const isGeminiTTSModel = (v: unknown): v is GeminiTTSModel => typeof v === 'string' && (GEMINI_TTS_MODELS as readonly string[]).includes(v);
Prevention
- Only '-tts' preview models emit audio; do not pass chat/completion Gemini ids.
- Populate the model selector from list_engines({ provider: 'gemini' }).
- Omit model to accept the safe default.
When it happens
Trigger: Passing model: 'gemini-1.5-flash' (a non-TTS Gemini model) or any id absent from GEMINI_TTS_MODELS. Only the specific '-tts' preview models are accepted.
Common situations: Using a chat/completion Gemini model id for TTS; passing a deprecated TTS model after Google renames it; typo; assuming any Gemini model can emit audio.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/216642a53c0dc01c.
Report an issue: GitHub.