HeyPuter/puter · error · HttpError
internal_error
internal_error
Error message
xAI API key not configured
What it means
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.
Source
Thrown at src/backend/drivers/ai-speech2txt/providers/xai/XAISpeechToTextProvider.ts:119
// xAI STT doesn't have a separate translation endpoint;
// delegate to transcribe which auto-detects language
return this.#handleTranscription(args);
}
#isHttpUrl(value: unknown): value is string {
return (
typeof value === 'string' &&
(value.startsWith('https://') || value.startsWith('http://'))
);
}
async #handleTranscription(args: ITranscribeArgs) {
if (args.test_mode) {
return { ...SAMPLE_TRANSCRIPT, model: 'xai-stt' };
}
if (!this.#apiKey) {
throw new HttpError(500, 'xAI API key not configured', {
legacyCode: 'internal_error',
});
}
this.requireFile(args);
const actor = this.requireActor();
// Determine if the input is an HTTP URL or a filesystem/data-URL reference
const isUrl = this.#isHttpUrl(args.file);
// For URLs we use xAI's native `url` param — no local fetch needed.
// For files we load from the Puter FS / data-URL.
let fileBuffer: Buffer | null = null;
let filename = 'audio.mp3';
let mimeType = 'audio/mpeg';
if (!isUrl) {
const loaded = await loadFileInput(View on GitHub (pinned to 908ec23eda)
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.
Example fix
// before (config.json, provider registered with no key)
"providers": { "xai": {} }
// after
"providers": { "xai": { "apiKey": "xai-..." } } Defensive patterns
Strategy: try-catch
Validate before calling
// Before relying on xAI STT, confirm the provider can actually transcribe.
// listModels() works without a key, so probe a test_mode call.
try {
await driver.transcribe({ provider: 'xai', file: url, test_mode: true });
} catch (e) {
// non-test calls will also fail; do not offer xAI STT to this user
}
// The real guard is server config: ensure providers.xai.apiKey is set at boot. Try / catch
try {
const result = await driver.transcribe({ provider: 'xai', file });
} catch (e) {
if (e?.fields?.legacyCode === 'internal_error' && /xAI API key not configured/.test(e.message)) {
// surface a user-friendly 'service unavailable' and alert ops about missing config
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- internal_error
- internal_error
- insufficient_funds
- errText || `xAI STT request failed (status ${response.status
- bad_request
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/b50242cd0774d317.
Report an issue: GitHub.