{"record":{"id":"b50242cd0774d317","repo":"HeyPuter/puter","slug":"internal-error-b50242","errorCode":"internal_error","errorMessage":"xAI API key not configured","messagePattern":"xAI API key not configured","errorType":"http","errorClass":"HttpError","httpStatus":500,"severity":"error","filePath":"src/backend/drivers/ai-speech2txt/providers/xai/XAISpeechToTextProvider.ts","lineNumber":119,"sourceCode":"        // xAI STT doesn't have a separate translation endpoint;\n        // delegate to transcribe which auto-detects language\n        return this.#handleTranscription(args);\n    }\n\n    #isHttpUrl(value: unknown): value is string {\n        return (\n            typeof value === 'string' &&\n            (value.startsWith('https://') || value.startsWith('http://'))\n        );\n    }\n\n    async #handleTranscription(args: ITranscribeArgs) {\n        if (args.test_mode) {\n            return { ...SAMPLE_TRANSCRIPT, model: 'xai-stt' };\n        }\n\n        if (!this.#apiKey) {\n            throw new HttpError(500, 'xAI API key not configured', {\n                legacyCode: 'internal_error',\n            });\n        }\n        this.requireFile(args);\n\n        const actor = this.requireActor();\n\n        // Determine if the input is an HTTP URL or a filesystem/data-URL reference\n        const isUrl = this.#isHttpUrl(args.file);\n\n        // For URLs we use xAI's native `url` param — no local fetch needed.\n        // For files we load from the Puter FS / data-URL.\n        let fileBuffer: Buffer | null = null;\n        let filename = 'audio.mp3';\n        let mimeType = 'audio/mpeg';\n\n        if (!isUrl) {\n            const loaded = await loadFileInput(","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-speech2txt/providers/xai/XAISpeechToTextProvider.ts#L101-L137","documentation":"Thrown by XAISpeechToTextProvider when a transcription is requested but the deployment never supplied an xAI API key. The provider still registers without a key so its model stays listable, but any real (non-test_mode) transcribe/translate call rejects at XAISpeechToTextProvider.ts:119 with HTTP 500. It is a server misconfiguration surfaced to the caller, not a caller input error.","triggerScenarios":"Calling the speech-to-text driver for provider 'xai' with a real audio file or URL while args.test_mode is falsy, on a server whose config.providers.xai has no apiKey/api_key/key. listModels() succeeds; only transcribe()/translate() hit this.","commonSituations":"Self-hosting Puter and enabling the xAI STT provider entry but leaving the credential blank; rotating secrets and forgetting to redeploy with the new key; misreading the config key name (it accepts apiKey, api_key, or key under providers.xai).","solutions":["Set providers.xai.apiKey (or api_key/key) to a valid xAI API key in the backend config and restart the server.","If you do not have xAI credentials, stop routing transcription requests to the xai provider and use a configured STT provider instead.","Pass test_mode: true in the request to confirm wiring without needing a key (returns a canned transcript).","Verify the key landed by checking server boot logs for the absence of an xAI init warning."],"exampleFix":"// before (config.json, provider registered with no key)\n\"providers\": { \"xai\": {} }\n// after\n\"providers\": { \"xai\": { \"apiKey\": \"xai-...\" } }","handlingStrategy":"try-catch","validationCode":"// Before relying on xAI STT, confirm the provider can actually transcribe.\n// listModels() works without a key, so probe a test_mode call.\ntry {\n  await driver.transcribe({ provider: 'xai', file: url, test_mode: true });\n} catch (e) {\n  // non-test calls will also fail; do not offer xAI STT to this user\n}\n// The real guard is server config: ensure providers.xai.apiKey is set at boot.","typeGuard":null,"tryCatchPattern":"try {\n  const result = await driver.transcribe({ provider: 'xai', file });\n} catch (e) {\n  if (e?.fields?.legacyCode === 'internal_error' && /xAI API key not configured/.test(e.message)) {\n    // surface a user-friendly 'service unavailable' and alert ops about missing config\n  } else throw e;\n}","preventionTips":["Validate provider credentials at boot and fail fast (or disable the provider) rather than letting calls hit the 500.","Expose configured providers via list() so clients can avoid unconfigured ones.","Use test_mode in smoke tests to catch missing keys before users do."],"tags":["config","credentials","xai","speech-to-text","server-error"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}