{"record":{"id":"1a5c74821db24c4c","repo":"HeyPuter/puter","slug":"internal-error-1a5c74","errorCode":"internal_error","errorMessage":"OpenAI API key not configured","messagePattern":"OpenAI API key not configured","errorType":"http","errorClass":"HttpError","httpStatus":500,"severity":"error","filePath":"src/backend/drivers/ai-speech2txt/providers/openai/OpenAISpeechToTextProvider.ts","lineNumber":158,"sourceCode":"        if (args.test_mode) {\n            return {\n                ...SAMPLE_TRANSCRIPT,\n                model:\n                    args.model ||\n                    (translate\n                        ? DEFAULT_TRANSLATE_MODEL\n                        : DEFAULT_TRANSCRIBE_MODEL),\n            };\n        }\n        if (args.stream) {\n            throw new HttpError(\n                400,\n                'Streaming transcription is not yet supported',\n                { legacyCode: 'bad_request' },\n            );\n        }\n        if (!this.#openai)\n            throw new HttpError(500, 'OpenAI API key not configured', {\n                legacyCode: 'internal_error',\n            });\n        this.requireFile(args);\n\n        const actor = this.requireActor();\n\n        const loaded = await loadFileInput(\n            this.deps.stores,\n            this.deps.fs,\n            actor,\n            args.file,\n            { maxBytes: MAX_AUDIO_FILE_SIZE, acceptWebInput: true },\n        );\n\n        const selectedModel =\n            args.model ||\n            (translate ? DEFAULT_TRANSLATE_MODEL : DEFAULT_TRANSCRIBE_MODEL);\n        const caps = MODEL_CAPS[selectedModel];","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-speech2txt/providers/openai/OpenAISpeechToTextProvider.ts#L140-L176","documentation":"The OpenAI provider's client #openai is null when no key was found across the openai-speech-to-text, openai-completion, and openai config shapes (readKey checks apiKey/secret_key/api_key/key in each). On a real (non-test_mode, non-stream) transcribe/translate the provider throws 500 / internal_error. The provider registers even without a key (so its model catalogue stays listable), so the failure surfaces only at call time.","triggerScenarios":"Any real STT call to the openai provider on a deployment with no OpenAI key in any of the three config shapes; a deployment whose only OpenAI config is under an unrecognized key name.","commonSituations":"Self-hosted Puter without OpenAI credentials; key under openai-completion.apiKey that is also missing; operator assumed listing models meant the provider was usable.","solutions":["Set providers.openai.apiKey (or openai-completion.apiKey / openai-speech-to-text.apiKey) and restart.","Call with test_mode: true until configured to verify the path end-to-end.","Route the call to a configured provider (e.g. xai) instead."],"exampleFix":"// config.json\n// before\n\"providers\": { \"openai\": {} }\n// after\n\"providers\": { \"openai\": { \"apiKey\": \"sk-...\" } }","handlingStrategy":"validation","validationCode":"// probe the path without spending credits\nawait driver.transcribe({ ...args, test_mode: true });\n// a successful test call followed by a 500 on the real call means the key is missing","typeGuard":null,"tryCatchPattern":"try {\n  await driver.transcribe(args);\n} catch (e) {\n  if (e?.legacyCode === 'internal_error' && /OpenAI API key not configured/.test(e?.message ?? '')) {\n    showProviderUnavailable('openai'); // or fall back to xai\n  } else throw e;\n}","preventionTips":["Boot-time health-check each provider's key.","Let users pick among configured providers only (use driver.list()).","Keep the test_mode plumbing so the path is exercisable without a key."],"tags":["config","credentials","openai","speech2txt"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}