Kuberwastaken/claurst · error · anyhow::Error
Transcription API returned
Error message
Transcription API returned {}: {} What it means
transcribe_audio sends the recorded audio to the configured Whisper-compatible endpoint and, on any non-success HTTP status, includes the status code and response body in the error. This surfaces upstream API failures (auth, rate limits, malformed requests, server errors) verbatim so the caller can diagnose them.
Solutions
- Read the status and body in the error to identify the cause (401 → fix key, 429 → back off, 404 → fix endpoint URL).
- Verify OPENAI_API_KEY validity and quota.
- Confirm WHISPER_ENDPOINT_URL points at the correct route (e.g. /inference for whisper.cpp).
- Add retry with backoff for 5xx/429 statuses.
Example fix
// before
let text = voice.record_and_transcribe().await?;
// after
match voice.record_and_transcribe().await {
Ok(t) => t,
Err(e) if e.to_string().contains("429") => {
tokio::time::sleep(Duration::from_secs(5)).await;
voice.record_and_transcribe().await?
}
Err(e) => return Err(e),
} Defensive patterns
Strategy: retry
Validate before calling
let url = std::env::var("WHISPER_ENDPOINT_URL")
.unwrap_or_else(|_| "https://api.openai.com/v1/audio/transcriptions".into());
// sanity-check reachability before recording
reqwest::get(url).await?.error_for_status()?; Try / catch
match voice.record_and_transcribe().await {
Err(e) if e.to_string().contains("returned 429") => {
backoff_retry().await
}
Err(e) if e.to_string().contains("returned 401") => {
prompt_for_api_key()?; voice.record_and_transcribe().await?
}
other => other,
} Prevention
- Validate API keys and endpoint URLs before long recordings.
- Implement backoff for 429/5xx responses.
- Check provider audio size limits before uploading.
When it happens
Trigger: POSTing audio to the transcription endpoint and receiving 4xx/5xx: invalid API key (401), quota exhausted (429), too-large payload (413), wrong endpoint URL (404), or transcription service outage (500/502).
Common situations: Expired/revoked OPENAI_API_KEY; local Whisper server not speaking the expected route; audio file exceeding provider size limit; rate limiting after heavy voice usage; typo'd WHISPER_ENDPOINT_URL.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Whisper API returned
- GrowthBook API returned status
- Bridge register: server returned
- Token exchange failed
- Token exchange failed
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/4d270fef66468bb0.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/core/src/voice.rs:534
let mut form = reqwest::multipart::Form::new()
.text("model", model.to_string())
.part("file", file_part);
if let Some(lang) = language {
form = form.text("language", lang.to_string());
}
let response = client
.post(url)
.bearer_auth(api_key)
.multipart(form)
.send()
.await?;
let status = response.status();
if !status.is_success() {
let body = response.text().await.unwrap_or_default();
return Err(anyhow::anyhow!(
"Transcription API returned {}: {}",
status,
body
));
}
let json: serde_json::Value = response.json().await?;
let text = json["text"]
.as_str()
.unwrap_or("")
.trim()
.to_string();
Ok(text)
}
// ---------------------------------------------------------------------------
// Global singleton
// ---------------------------------------------------------------------------
View on GitHub (pinned to b0637c97ec)