HeyPuter/puter · error · HttpError
upstreamMessage ?? `ElevenLabs request failed (status ${resp
Error message
upstreamMessage ?? `ElevenLabs request failed (status ${response.status})` What it means
Generic upstream-failure path in ElevenLabsTTSProvider.request. Whenever the ElevenLabs REST call returns non-2xx, the response body is parsed and re-thrown as an HttpError. legacyCode maps the upstream status (5xx -> upstream_provider_unavailable, 401/403 -> upstream_auth_failed exposed as 500, 429 -> upstream_rate_limited exposed as 429, other 4xx -> upstream_bad_request exposed as 400). The message prefers ElevenLabs' own detail.message/message; otherwise 'ElevenLabs request failed (status N)'. fields includes provider, upstreamStatus, and upstreamCode.
Source
Thrown at src/backend/drivers/ai-tts/providers/elevenlabs/ElevenLabsTTSProvider.ts:130
(detail as any)?.detail?.code ?? (detail as any)?.code;
const upstreamMessage =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(detail as any)?.detail?.message ?? (detail as any)?.message;
const legacyCode =
response.status >= 500
? 'upstream_provider_unavailable'
: response.status === 401 || response.status === 403
? 'upstream_auth_failed'
: response.status === 429
? 'upstream_rate_limited'
: 'upstream_bad_request';
const exposedStatus =
legacyCode === 'upstream_rate_limited'
? 429
: legacyCode === 'upstream_auth_failed'
? 500
: 400;
throw new HttpError(
exposedStatus,
upstreamMessage ??
`ElevenLabs request failed (status ${response.status})`,
{
legacyCode,
fields: {
provider: 'elevenlabs',
upstreamStatus: response.status,
upstreamCode,
},
},
);
}
async listVoices(): Promise<ITTSVoice[]> {
const res = await this.request('/v1/voices');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = await res.json();View on GitHub (pinned to 908ec23eda)
Solutions
- Inspect fields.upstreamStatus and fields.legacyCode: 401/403 -> fix/rotate the configured elevenlabs apiKey; 429 -> back off; 4xx -> fix voice_id/model/settings; 5xx -> retry.
- For voice_not_found, confirm the voiceId exists via list_voices({ provider: 'elevenlabs' }) and use a returned id.
- For 429, implement exponential backoff or reduce concurrency.
- Check server logs for '[ElevenLabsTTSProvider] request failed' which carries the full upstream detail.
- If using a custom apiBaseUrl, confirm it points to a compatible ElevenLabs-compatible endpoint.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await driver.synthesize({ text, provider: 'elevenlabs', voice: voiceId });
} catch (e) {
const code = e?.fields?.legacyCode;
if (code === 'upstream_rate_limited') {
// exponential backoff, then retry
} else if (code === 'upstream_auth_failed') {
// alert ops: configured elevenlabs key is invalid/expired
} else if (code === 'upstream_bad_request') {
// likely bad voice_id/model — re-fetch via list_voices and retry
} else if (code === 'upstream_provider_unavailable') {
// transient ElevenLabs outage — bounded retry
} else throw e;
} Prevention
- Fetch voice ids from list_voices rather than hardcoding, so deleted voices don't cause upstream_bad_request.
- Use only models present in the cost table (list_engines).
- Branch on fields.legacyCode; remember upstream 401/403 is exposed as 500 (key problem).
- Watch server logs for '[ElevenLabsTTSProvider] request failed' with the full upstream detail.
When it happens
Trigger: ElevenLabs rejects a request: unknown/invalid voice_id (404 -> upstream_bad_request), unsupported model_id, malformed voice_settings, bad/expired xi-api-key (401/403), quota/rate limit (429), or ElevenLabs outage (5xx).
Common situations: Hardcoding a voice id that was deleted from the ElevenLabs account; using a model the key's tier doesn't allow; stale key; burst traffic hitting 429; transient ElevenLabs 5xx. Note the exposed 500 for 401/403 hides that the real cause is the configured key.
Related errors
- errText || `xAI STT request failed (status ${response.status
- ElevenLabs returned ${response.status}
- unauthorized
- field_required
- field_invalid
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/b9de17b87a7f25c1.
Report an issue: GitHub.