HeyPuter/puter · error · HttpError

errText || `xAI STT request failed (status ${response.status

Error message

errText || `xAI STT request failed (status ${response.status})`

What it means

Surfaced when the upstream xAI /v1/stt call returns a non-2xx response. The provider reads the error body and re-throws an HttpError whose legacyCode maps the upstream status: 5xx -> upstream_provider_unavailable, 401/403 -> upstream_auth_failed (exposed as 500), 429 -> upstream_rate_limited (exposed as 429), other 4xx -> upstream_bad_request (exposed as 400). The message is xAI's errText when present, else a generic 'xAI STT request failed (status N)'. The original upstream status is attached in fields.upstreamStatus.

Source

Thrown at src/backend/drivers/ai-speech2txt/providers/xai/XAISpeechToTextProvider.ts:217

                `[XAISpeechToTextProvider] API returned ${response.status}: ${errText}`,
            );
            // Mirrors ElevenLabs / XAITTS — map upstream status to an
            // `upstream_*` HttpError so the alarm gate skips it.
            const legacyCode =
                response.status >= 500
                    ? 'upstream_provider_unavailable'
                    : response.status === 401 || response.status === 403
                      ? 'upstream_auth_failed'
                      : response.status === 429
                        ? 'upstream_rate_limited'
                        : 'upstream_bad_request';
            const exposedStatus =
                legacyCode === 'upstream_rate_limited'
                    ? 429
                    : legacyCode === 'upstream_auth_failed'
                      ? 500
                      : 400;
            throw new HttpError(
                exposedStatus,
                errText || `xAI STT request failed (status ${response.status})`,
                {
                    legacyCode,
                    fields: {
                        provider: 'xai',
                        upstreamStatus: response.status,
                    },
                },
            );
        }

        const result = await response.json();

        // Meter actual usage using returned duration, or estimated
        const actualSeconds =
            typeof result.duration === 'number'
                ? Math.ceil(result.duration)

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Inspect fields.upstreamStatus and fields.legacyCode in the error: 401/403 -> rotate/fix the configured xAI key; 429 -> slow down or back off; 4xx -> fix the audio payload/format; 5xx -> retry with backoff.
  2. For upstream_rate_limited, implement exponential backoff or queue requests below xAI's rate ceiling.
  3. For upstream_auth_failed, update providers.xai.apiKey with a valid key and restart.
  4. For upstream_bad_request, confirm the audio is under 500MB and in a format xAI accepts (mp3, wav, etc.), and that multipart fields (channels, format, diarize) are valid.
  5. Check server logs for the '[XAISpeechToTextProvider] API returned N: ...' line which carries the full upstream body.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const t = await driver.transcribe({ provider: 'xai', file });
} catch (e) {
  const code = e?.fields?.legacyCode;
  if (code === 'upstream_rate_limited') {
    // back off and retry with exponential delay
  } else if (code === 'upstream_auth_failed') {
    // alert ops: the configured xAI key is bad/revoked
  } else if (code === 'upstream_provider_unavailable') {
    // transient xAI outage — retry a limited number of times
  } else if (code === 'upstream_bad_request') {
    // fix the audio payload/format; check fields.upstreamStatus for detail
  } else throw e;
}

Prevention

When it happens

Trigger: xAI rejects the transcription: invalid/expired configured API key (401/403), quota exhausted (429), unsupported audio format or malformed multipart (4xx), or an xAI-side outage (5xx). Also triggered by audio exceeding xAI limits or unsupported codecs.

Common situations: The configured xAI key was revoked or is for the wrong workspace; a 429 during burst traffic; sending an audio format xAI cannot decode; transient xAI 5xx incidents. The exposed 500 for auth failures often masks the real cause (bad key) since upstream 401 is intentionally hidden.

Related errors


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