{"record":{"id":"6836233277aeef51","repo":"HeyPuter/puter","slug":"internal-error-683623","errorCode":"internal_error","errorMessage":"ElevenLabs API key not configured","messagePattern":"ElevenLabs API key not configured","errorType":"http","errorClass":"HttpError","httpStatus":500,"severity":"error","filePath":"src/backend/drivers/ai-speech2speech/VoiceChangerDriver.ts","lineNumber":133,"sourceCode":"            !PROVIDERS.includes(\n                args.provider\n                    .trim()\n                    .toLowerCase() as (typeof PROVIDERS)[number],\n            )\n        ) {\n            throw new HttpError(\n                400,\n                `Speech-to-speech provider not found: ${args.provider}. Available: ${PROVIDERS.join(', ')}`,\n                { legacyCode: 'bad_request' },\n            );\n        }\n\n        if (args.test_mode) {\n            return { url: SAMPLE_AUDIO_URL, content_type: 'audio/mpeg' };\n        }\n\n        if (!this.#apiKey) {\n            throw new HttpError(500, 'ElevenLabs API key not configured', {\n                legacyCode: 'internal_error',\n            });\n        }\n\n        const actor = Context.get('actor');\n        if (!actor)\n            throw new HttpError(401, 'Authentication required', {\n                legacyCode: 'unauthorized',\n            });\n\n        if (!args.audio) {\n            throw new HttpError(400, '`audio` is required', {\n                legacyCode: 'bad_request',\n            });\n        }\n\n        const loaded = await loadFileInput(\n            this.stores,","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-speech2speech/VoiceChangerDriver.ts#L115-L151","documentation":"The call reached the ElevenLabs code path but this.#apiKey is null: config.providers.elevenlabs had no apiKey (nor api_key/key) when onServerStart ran at boot. The driver throws 500 / internal_error because a missing server-side credential is an operator defect, not a caller mistake. It fires AFTER the test_mode short-circuit, so a test call still succeeds without a key.","triggerScenarios":"Any real (test_mode falsy) convert() on a deployment whose config.providers.elevenlabs block is absent or has no key field, or whose key resolved to an empty/falsy string.","commonSituations":"Self-hosted Puter without ElevenLabs credentials in config.json; the env var never wired into the config loader; key field named with an unexpected casing the lookup (apiKey/api_key/key) does not catch.","solutions":["Set providers.elevenlabs.apiKey (or api_key / key) in the backend config and restart so onServerStart re-reads it.","Verify the config file the running process actually loads (not a stale transpiled build).","Until configured, call with test_mode: true to return the sample audio URL, or disable the feature in the UI."],"exampleFix":"// config.json\n// before\n\"providers\": { \"elevenlabs\": {} }\n// after\n\"providers\": { \"elevenlabs\": { \"apiKey\": \"xi-...\" } }","handlingStrategy":"validation","validationCode":"// probe the path without spending credits\nawait driver.convert({ ...args, test_mode: true });\n// if the test call returns sample audio but a real call 500s with\n// 'ElevenLabs API key not configured', the key is missing at the server","typeGuard":null,"tryCatchPattern":"try {\n  await driver.convert(args);\n} catch (e) {\n  if (e?.legacyCode === 'internal_error' && /API key not configured/.test(e?.message ?? '')) {\n    showFeatureUnavailable('speech-to-speech'); // alert ops\n  } else throw e;\n}","preventionTips":["Health-check upstream credentials at boot, not at first user call.","Keep the test_mode plumbing so the path is exercisable without a key.","Document the config key names the loader actually accepts (apiKey/api_key/key)."],"tags":["config","credentials","elevenlabs","speech2speech"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}