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

  1. Set providers.xai.apiKey (or api_key/key) to a valid xAI API key in the backend config and restart the server.
  2. If you do not have xAI credentials, stop routing transcription requests to the xai provider and use a configured STT provider instead.
  3. Pass test_mode: true in the request to confirm wiring without needing a key (returns a canned transcript).
  4. 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

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


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/b50242cd0774d317. Report an issue: GitHub.