HeyPuter/puter · error · HttpError
bad_request
bad_request
Error message
TTS provider not configured: ${providerName}. Available: ${Object.keys(this.#providers).join(', ')} What it means
After #resolveProvider returns a canonical provider name, TTSDriver looks it up in #providers (the providers actually instantiated from config). If the name is valid but no provider instance exists — because its credentials were never supplied or its constructor threw during boot — it throws HTTP 400 (legacyCode bad_request), listing the providers that ARE configured. Distinct from 425: here the name normalized fine; it just isn't configured.
Source
Thrown at src/backend/drivers/ai-tts/TTSDriver.ts:163
}
/**
* Synthesize speech from text, routed to the provider named by `provider`
* (or the default when none is given).
*/
async synthesize(
args: ISynthesizeArgs,
): Promise<DriverStreamResult | { url: string; content_type: string }> {
const actor = Context.get('actor');
if (!actor)
throw new HttpError(401, 'Authentication required', {
legacyCode: 'unauthorized',
});
const providerName = this.#resolveProvider(args);
const provider = this.#providers[providerName];
if (!provider) {
throw new HttpError(
400,
`TTS provider not configured: ${providerName}. Available: ${Object.keys(this.#providers).join(', ')}`,
{ legacyCode: 'bad_request' },
);
}
return provider.synthesize(
this.#providerArgs(providerName, args),
) as Promise<
DriverStreamResult | { url: string; content_type: string }
>;
}
// -- Provider routing --------------------------------------------
/**
* Decide which provider handles a call. An explicit `provider` wins, then
* an `engine` that names a provider (a long-standing shorthand), then theView on GitHub (pinned to 908ec23eda)
Solutions
- Supply credentials for the requested provider in config.providers (e.g. aws-polly needs aws.access_key and aws.secret_key).
- Call the driver's list() method first to see which providers are actually configured, then route to one of them.
- Omit the provider argument to let #defaultProvider pick a configured one.
- Check boot logs for '[TTSDriver] Failed to init ... provider' warnings indicating a construction failure.
Example fix
// before
await driver.synthesize({ text: 'hi', provider: 'aws-polly' }); // not configured
// after — let the default (or a configured provider) handle it
await driver.synthesize({ text: 'hi' }); Defensive patterns
Strategy: validation
Validate before calling
// Ask the driver which providers are actually configured, then pick one.
const configured = await driver.list(); // returns Object.keys(#providers)
if (!configured.includes(targetProvider)) {
// fall back to a configured provider or surface 'unavailable'
}
await driver.synthesize({ text: 'hi', provider: configured[0] }); Try / catch
try {
await driver.synthesize({ text: 'hi', provider: name });
} catch (e) {
if (e?.fields?.legacyCode === 'bad_request' && /not configured/.test(e.message)) {
const available = await driver.list();
// retry with an available provider or notify the user
} else throw e;
} Prevention
- Call list() at app start to learn which providers are live.
- Omit provider to let #defaultProvider choose a configured one.
- Check boot logs for 'Failed to init ... provider' warnings that explain why a provider is missing.
When it happens
Trigger: Requesting provider 'aws-polly' when no access_key/secret_key were given; 'elevenlabs' with no apiKey; 'gemini' with no key; or any provider whose constructor threw during #registerProviders (logged as a console.warn on boot).
Common situations: Default provider is aws-polly but the deployment only configured openai — any call that resolves to aws-polly fails; a key was typo'd so construction logged a warning and the provider stayed unregistered; requesting a provider by alias that maps to an unconfigured canonical name.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/e6f6734c1931003a.
Report an issue: GitHub.