zeroclaw-labs/zeroclaw · warning · anyhow::Error
audio download failed: {}
Error message
audio download failed: {} What it means
The initial download of a Lark audio resource (im/v1/messages/{message_id}/resources) returned non-2xx and did not look like a stale-token response, so no refresh was attempted. Only the status is included. This is the no-refresh twin of error 106 and usually indicates the resource identifier or access is wrong, not the token.
Source
Thrown at crates/zeroclaw-channels/src/lark.rs:1961
self.invalidate_token().await;
let token = self.get_tenant_access_token().await?;
let resp = self
.http_client()
.get(&url)
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
if !resp.status().is_success() {
anyhow::bail!(
"audio download failed after token refresh: {}",
resp.status()
);
}
let bytes = Self::stream_audio_bytes(resp).await?;
return Ok((bytes, inferred_audio_filename(file_key)));
}
anyhow::bail!("audio download failed: {}", status);
}
let bytes = Self::stream_audio_bytes(resp).await?;
Ok((bytes, inferred_audio_filename(file_key)))
}
async fn try_transcribe_audio_message(
&self,
message_id: &str,
content: &str,
manager: &super::transcription::TranscriptionManager,
) -> Option<String> {
let file_key = serde_json::from_str::<serde_json::Value>(content)
.ok()
.and_then(|v| {
v.get("file_key")
.and_then(|k| k.as_str())
.map(str::to_owned)
})?;View on GitHub (pinned to 88bb9c8533)
Solutions
- Branch on the reported status: 404 -> skip (expired resource); 403 -> grant and publish the message-resource read scope; 400 -> verify file_key handling; 5xx -> retry later.
- Process audio events promptly to stay inside Lark's resource retention window.
- If this fires for every audio message, test one file_key manually with a fresh token to isolate scope vs expiry.
Defensive patterns
Strategy: fallback
Type guard
fn is_lark_audio_download_error(err: &anyhow::Error) -> bool {
err.to_string().contains("audio download failed")
} Try / catch
if is_lark_audio_download_error(&e) {
tracing::warn!(error = %e, "lark audio unavailable (expired/forbidden); continuing without it");
return Ok(());
} Prevention
- Download resources as soon as the event arrives, not after full pipeline processing.
- Separate 'media fetch' failures from 'send' failures in alerting; only the latter block replies.
- Verify message-resource scopes before going live.
When it happens
Trigger: 404 for an expired or already-deleted message resource, 403 for a resource the bot lacks permission to read, 400 for an invalid file_key, or 5xx during Lark incidents.
Common situations: Delayed processing after webhook backlogs, users deleting messages before the bot fetches audio, missing message-resource read scope on the app.
Related errors
- audio download failed after token refresh: {}
- audio download failed ({status}) for message {message_id}
- tenant_access_token request failed: status={status}, body={d
- bot info request failed after token refresh: status={retry_s
- bot info request failed: status={status}, body={body}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/f64258b6cf7bb85b.
Report an issue: GitHub.