HeyPuter/puter · error · HttpError
internal_error
internal_error
Error message
No cost data for model: ${model} What it means
After the model passes the GEMINI_TTS_MODELS check, GeminiTTSProvider looks up GEMINI_TTS_COSTS[model]; if missing it throws HTTP 500 (legacyCode internal_error). This indicates an internal inconsistency: a model is advertised in GEMINI_TTS_MODELS but has no entry in the GEMINI_TTS_COSTS table. It is a code/config bug in the provider, not a caller error.
Source
Thrown at src/backend/drivers/ai-tts/providers/gemini/GeminiTTSProvider.ts:195
400,
`Invalid voice: ${voice}. Expected: ${GEMINI_TTS_VOICES.map(({ id }) => id).join(', ')}`,
{
legacyCode: 'field_invalid',
fields: {
key: 'voice',
expected: GEMINI_TTS_VOICES.map(({ id }) => id).join(
', ',
),
got: voice,
},
},
);
}
const actor = Context.get('actor')!;
const costs = GEMINI_TTS_COSTS[model];
if (!costs) {
throw new HttpError(500, `No cost data for model: ${model}`, {
legacyCode: 'internal_error',
});
}
// Estimate input tokens (~4 chars per token) and a rough output
// audio duration (~150 words/min, 25 tokens/sec).
const estimatedInputTokens = Math.max(1, Math.ceil(text.length / 4));
const wordCount = text.split(/\s+/).length;
const estimatedDurationSec = Math.max(1, (wordCount / 150) * 60);
const estimatedOutputTokens = Math.ceil(estimatedDurationSec * 25);
const estimatedInputCostCents =
(estimatedInputTokens / 1_000_000) * costs.input;
const estimatedOutputCostCents =
(estimatedOutputTokens / 1_000_000) * costs.output_audio;
const estimatedTotalMicroCents = this.#toMicroCents(
estimatedInputCostCents + estimatedOutputCostCents,
);View on GitHub (pinned to 908ec23eda)
Solutions
- Add the missing model to GEMINI_TTS_COSTS in src/backend/drivers/ai-tts/providers/gemini/costs.ts with input and output_audio rates.
- Ensure GEMINI_TTS_MODELS and GEMINI_TTS_COSTS stay in sync whenever a model is added or renamed (treat them as one unit).
- As a caller workaround until the bug is fixed, select a different model that has a cost entry.
- Add a unit test asserting every GEMINI_TTS_MODELS id has a GEMINI_TTS_COSTS entry to prevent regression.
Example fix
// costs.ts — before
export const GEMINI_TTS_COSTS = {
'gemini-2.5-flash-preview-tts': { input: 0.5, output_audio: 3 },
};
// after — add the missing model that GEMINI_TTS_MODELS advertises
export const GEMINI_TTS_COSTS = {
'gemini-2.5-flash-preview-tts': { input: 0.5, output_audio: 3 },
'gemini-3.1-flash-tts-preview': { input: 0.5, output_audio: 3 },
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Caller-side: avoid models the server cannot price by using a known-cost model.
const KNOWN_COST_GEMINI_MODELS = ['gemini-2.5-flash-preview-tts', 'gemini-2.5-pro-preview-tts'];
function synthesizeGemini(text, model = 'gemini-2.5-flash-preview-tts') {
if (!KNOWN_COST_GEMINI_MODELS.includes(model)) {
// pick a known-cost default rather than risk a 500
model = 'gemini-2.5-flash-preview-tts';
}
return driver.synthesize({ text, provider: 'gemini', model });
}
// Server-side fix: add the missing entry to GEMINI_TTS_COSTS in costs.ts. Try / catch
try {
await driver.synthesize({ text, provider: 'gemini', model });
} catch (e) {
if (e?.status === 500 && /No cost data for model/.test(e.message)) {
// internal inconsistency — file a bug, fall back to a known-cost model
await driver.synthesize({ text, provider: 'gemini', model: 'gemini-2.5-flash-preview-tts' });
} else throw e;
} Prevention
- Treat GEMINI_TTS_MODELS and GEMINI_TTS_COSTS as one unit: add/remove in lockstep.
- Add a unit test asserting every advertised model has a cost entry.
- When selecting a model programmatically, prefer ones with a known cost row.
When it happens
Trigger: A developer added a new model id to GEMINI_TTS_MODELS but forgot to add its pricing to GEMINI_TTS_COSTS (in costs.js), then a caller (or default) selects that model. The voice/model validation passes; only the cost lookup fails.
Common situations: A new Gemini TTS preview model was added to the model list without its cost row; a rename that updated one table but not the other; refactoring that split the tables.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/15aa04ab3e8f578e.
Report an issue: GitHub.