zeroclaw-labs/zeroclaw · warning · anyhow::Error
audio download exceeds {} byte limit
Error message
audio download exceeds {} byte limit What it means
stream_audio_bytes downloads a Lark audio resource chunk by chunk and aborts as soon as the accumulated bytes exceed MAX_LARK_AUDIO_BYTES, a compile-time constant of 25 MiB (25 * 1024 * 1024, lark.rs:23). The limit protects the process from buffering unbounded downloads in memory, since the whole body is collected into a Vec<u8> for transcription. It is not configurable at runtime.
Source
Thrown at crates/zeroclaw-channels/src/lark.rs:1913
}
Err(err) => {
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_outcome(::zeroclaw_log::EventOutcome::Unknown)
.with_attrs(::serde_json::json!({"err": err.to_string()})),
"failed to resolve bot open_id: ; mention_only group messages will be ignored"
);
}
}
}
async fn stream_audio_bytes(mut resp: reqwest::Response) -> anyhow::Result<Vec<u8>> {
let mut body = Vec::new();
while let Some(chunk) = resp.chunk().await? {
body.extend_from_slice(&chunk);
if body.len() as u64 > MAX_LARK_AUDIO_BYTES {
anyhow::bail!("audio download exceeds {} byte limit", MAX_LARK_AUDIO_BYTES);
}
}
Ok(body)
}
async fn download_audio_resource(
&self,
message_id: &str,
file_key: &str,
) -> anyhow::Result<(Vec<u8>, String)> {
let url = format!(
"{}/im/v1/messages/{message_id}/resources/{file_key}?type=file",
self.api_base()
);
let token = self.get_tenant_access_token().await?;
let resp = self
.http_client()
.get(&url)View on GitHub (pinned to 88bb9c8533)
Solutions
- Treat as expected degradation: skip transcription for oversized audio and, if desired, notify the user.
- If the pipeline genuinely needs larger audio, raise the const MAX_LARK_AUDIO_BYTES in crates/zeroclaw-channels/src/lark.rs and rebuild, keeping in mind the full body is held in memory.
- Check Content-Length before streaming so oversized resources are rejected before the download starts.
- Verify the file_key/content_type mapping is not misrouting large non-audio media into the audio path.
Example fix
// before (crates/zeroclaw-channels/src/lark.rs:23) const MAX_LARK_AUDIO_BYTES: u64 = 25 * 1024 * 1024; // after (raises the in-memory cap; whole body is still buffered) const MAX_LARK_AUDIO_BYTES: u64 = 50 * 1024 * 1024;
Defensive patterns
Strategy: validation
Validate before calling
// Reject oversized downloads before streaming anything
if let Some(len) = resp.content_length() {
anyhow::ensure!(
len <= MAX_LARK_AUDIO_BYTES,
"lark audio content-length {len} exceeds {} cap; skipping download",
MAX_LARK_AUDIO_BYTES
);
} Type guard
fn is_audio_size_error(err: &anyhow::Error) -> bool {
err.to_string().contains("audio download exceeds")
} Try / catch
if is_audio_size_error(&e) {
// expected degradation, not a fault: skip transcription, keep processing the message
tracing::warn!(error = %e, "oversized lark audio; skipping transcription");
return Ok(());
} Prevention
- Check Content-Length before downloading large media.
- Keep transcription optional: audio failure must not fail the whole message turn.
- If raising the cap, size heap headroom for the full buffered Vec<u8>.
When it happens
Trigger: An inbound voice/audio message whose resource exceeds 25 MiB: very long voice notes, high-bitrate audio files, or a file_key/content_type mapping that routes a large video into the audio download path.
Common situations: Users forwarding long recordings, users sending audio files (m4a/mp3) instead of recorded voice notes, or upstream content-type changes reclassifying large media as audio.
Related errors
- audio exceeds {} byte limit for message {message_id}
- audio download failed after token refresh: {}
- audio download failed: {}
- Audio file too large ({} bytes, max {MAX_AUDIO_BYTES})
- Audio file too large ({} bytes, global max {})
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/2a3a2b734b10f82e.
Report an issue: GitHub.