{"record":{"id":"797dec36c4091cde","repo":"HeyPuter/puter","slug":"elevenlabs-returned-response-status","errorCode":null,"errorMessage":"ElevenLabs returned ${response.status}","messagePattern":"ElevenLabs returned (.+?)","errorType":"http","errorClass":"HttpError","httpStatus":null,"severity":"error","filePath":"src/backend/drivers/ai-speech2speech/VoiceChangerDriver.ts","lineNumber":289,"sourceCode":"            // as 400 like the TTS provider does — user can't act on\n            // them, but it's not our bug either).\n            const legacyCode =\n                response.status >= 500\n                    ? 'upstream_provider_unavailable'\n                    : response.status === 401 || response.status === 403\n                      ? 'upstream_auth_failed'\n                      : response.status === 429\n                        ? 'upstream_rate_limited'\n                        : 'upstream_bad_request';\n            const exposedStatus =\n                legacyCode === 'upstream_rate_limited'\n                    ? 429\n                    : legacyCode === 'upstream_auth_failed'\n                      ? 500\n                      : legacyCode === 'upstream_provider_unavailable'\n                        ? 400\n                        : response.status;\n            throw new HttpError(exposedStatus, message, {\n                legacyCode,\n                fields: {\n                    provider: 'elevenlabs',\n                    upstreamStatus: response.status,\n                },\n            });\n        }\n\n        const arrayBuffer = await response.arrayBuffer();\n        const stream = Readable.from(Buffer.from(arrayBuffer));\n        this.services.metering.incrementUsage(\n            actor,\n            usageKey,\n            estimatedSeconds,\n            ucentsPerSecond * estimatedSeconds,\n        );\n\n        return {","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-speech2speech/VoiceChangerDriver.ts#L271-L307","documentation":"After the upstream fetch, if response.ok is false the driver wraps the ElevenLabs status into a tagged legacyCode: upstream_provider_unavailable (ElevenLabs 5xx, exposed as 400), upstream_auth_failed (ElevenLabs 401/403, exposed as 500), upstream_rate_limited (429, exposed as 429), otherwise upstream_bad_request (exposed as the raw status). The message is ElevenLabs' detail field when present, else 'ElevenLabs returned <status>'. provider and upstreamStatus are attached as fields.","triggerScenarios":"ElevenLabs returns 429 (quota/rate), 401/403 (our key revoked or invalid), 400 (a voice/model it rejects), or 5xx (ElevenLabs outage). The exposed HTTP status depends on the mapped legacyCode, not always the upstream status.","commonSituations":"Burst traffic hitting ElevenLabs rate limits; an expired or rotated API key; an ElevenLabs incident; a voice id that exists but is disabled on the account.","solutions":["For 429 (upstream_rate_limited): backoff and retry with jitter; reduce concurrency.","For 401/403 (upstream_auth_failed): rotate the ElevenLabs API key in config.","For 5xx (upstream_provider_unavailable): surface a 'provider unavailable' message and check the ElevenLabs status page.","For 400 (upstream_bad_request): inspect fields.upstreamStatus and the message detail; fix the offending voice/model/params."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function convertWithRetry(args, tries = 3) {\n  for (let i = 0; i < tries; i++) {\n    try {\n      return await driver.convert(args);\n    } catch (e) {\n      const retriable = e?.legacyCode === 'upstream_rate_limited'\n        || e?.legacyCode === 'upstream_provider_unavailable';\n      if (retriable && i < tries - 1) {\n        await new Promise(r => setTimeout(r, 2 ** i * 500 + Math.random() * 250));\n        continue;\n      }\n      throw e;\n    }\n  }\n}","preventionTips":["Retry only on upstream_rate_limited / upstream_provider_unavailable; never retry upstream_bad_request.","Exponential backoff with jitter to avoid amplifying rate limits.","Log fields.upstreamStatus to distinguish upstream causes in monitoring."],"tags":["upstream","network","elevenlabs","speech2speech"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}