zeroclaw-labs/zeroclaw · error
Deepgram API error ({}): {}
Error message
Deepgram API error ({}): {} What it means
DeepgramProvider::transcribe() POSTs the audio to the Deepgram API and bails when the response status is not 2xx, embedding the HTTP status plus the 'err_msg' or 'error' field from Deepgram's JSON body. This is Deepgram's own error surfacing — the request reached Deepgram and was rejected. The provider was already constructed successfully, so registration/config shape was fine; the failure is authentication, payload, or quota.
Source
Thrown at crates/zeroclaw-channels/src/transcription.rs:415
.header("Content-Type", mime)
.body(audio_data.to_vec())
.timeout(std::time::Duration::from_secs(TRANSCRIPTION_TIMEOUT_SECS))
.send()
.await
.context("Failed to send transcription request to Deepgram")?;
let status = resp.status();
let body: serde_json::Value = resp
.json()
.await
.context("Failed to parse Deepgram response")?;
if !status.is_success() {
let error_msg = body["err_msg"]
.as_str()
.or_else(|| body["error"].as_str())
.unwrap_or("unknown error");
bail!("Deepgram API error ({}): {}", status, error_msg);
}
let text = body["results"]["channels"][0]["alternatives"][0]["transcript"]
.as_str()
.context("Deepgram response missing transcript field")?
.to_string();
Ok(text)
}
}
// ── AssemblyAiProvider ──────────────────────────────────────────
/// AssemblyAI STT API transcription_provider.
pub struct AssemblyAiProvider {
alias: String,
api_key: String,
}View on GitHub (pinned to 88bb9c8533)
Solutions
- Read {status}: 401/403 means the api_key in [transcription.deepgram] is wrong or revoked — update it
- 400 means Deepgram rejected the audio itself — verify the file extension matches the real encoding (re-encode with ffmpeg if needed)
- 402 means out of quota — check billing in the Deepgram console
- 429/5xx are transient — retry the transcription with backoff
Example fix
# before [transcription.deepgram] api_key = "expired-key-abc" # after [transcription.deepgram] api_key = "valid-key-from-console"
Defensive patterns
Strategy: try-catch
Try / catch
match provider.transcribe(&audio, name).await {
Ok(text) => Ok(text),
Err(e) => {
let msg = e.to_string();
if msg.contains("401") || msg.contains("403") {
Err(anyhow!("deepgram credentials rejected — check [transcription.deepgram].api_key"))
} else if msg.contains("429") || msg.contains("50") {
retry_with_backoff(|| provider.transcribe(&audio, name)).await
} else {
Err(e)
}
}
} Prevention
- Validate the Deepgram key once at startup with a minimal /v1/listen request
- Monitor Deepgram credit balance — 402 arrives without warning
- Re-encode unusual codecs to mp3/flac before uploading
When it happens
Trigger: POST https://api.deepgram.com/v1/listen returns non-2xx: 401 with invalid [transcription.deepgram] api_key; 400 when the audio bytes do not match a recognizable codec or the mimetype/extension is wrong; 402 when the Deepgram account is out of credits; 429 rate limited.
Common situations: Expired or mistyped Deepgram API key; free-tier credits exhausted; .oga/.ogg files whose actual codec is not Opus/FLAC/Ogg and Deepgram cannot sniff them; key rotated in the Deepgram console but config not updated.
Related errors
- AssemblyAI upload error ({}): {}
- AssemblyAI transcription error ({}): {}
- Google STT API error ({}): {}
- AssemblyAI poll error ({}): {}
- Transcription API error ({}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/ddebfacc3886038b.
Report an issue: GitHub.