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

  1. 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.
  2. For voice_not_found, confirm the voiceId exists via list_voices({ provider: 'elevenlabs' }) and use a returned id.
  3. For 429, implement exponential backoff or reduce concurrency.
  4. Check server logs for '[ElevenLabsTTSProvider] request failed' which carries the full upstream detail.
  5. 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

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


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/b9de17b87a7f25c1. Report an issue: GitHub.