zeroclaw-labs/zeroclaw · warning · anyhow::Error
audio exceeds {} byte limit for message {message_id}
Error message
audio exceeds {} byte limit for message {message_id} What it means
LINE channel: download_audio_content streams the content response chunk by chunk and aborts once the accumulated bytes exceed MAX_LINE_AUDIO_BYTES, a compile-time constant of 25 MiB (line.rs:18). The guard exists because the entire body is buffered into a Vec<u8> for transcription; it protects memory, not the API. The message includes the limit and the message_id.
Source
Thrown at crates/zeroclaw-channels/src/line.rs:208
) -> anyhow::Result<Vec<u8>> {
let url = format!("{content_api_base_url}/v2/bot/message/{message_id}/content");
let resp = client
.get(&url)
.bearer_auth(channel_access_token)
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
anyhow::bail!("audio download failed ({status}) for message {message_id}");
}
let mut bytes = Vec::new();
let mut stream = resp;
while let Some(chunk) = stream.chunk().await? {
bytes.extend_from_slice(&chunk);
if bytes.len() as u64 > MAX_LINE_AUDIO_BYTES {
anyhow::bail!(
"audio exceeds {} byte limit for message {message_id}",
MAX_LINE_AUDIO_BYTES
);
}
}
Ok(bytes)
}
fn build_webhook_router(state: Arc<LineState>) -> axum::Router {
use axum::{Router, routing::post};
Router::new()
.route("/line/webhook", post(handle_webhook))
.with_state(state)
}
/// Check whether `user_id` is in the LINE peer allowlist resolved from
/// canonical config state at call-time. LINE user IDs are case-sensitive.
fn is_line_user_allowed(state: &LineState, user_id: &str) -> bool {View on GitHub (pinned to 88bb9c8533)
Solutions
- Treat as expected degradation: skip transcription for oversized audio and optionally notify the user.
- If larger audio must be supported, raise const MAX_LINE_AUDIO_BYTES in crates/zeroclaw-channels/src/line.rs and rebuild, accounting for memory.
- Pre-check Content-Length before downloading to reject oversized content immediately.
Example fix
// before (crates/zeroclaw-channels/src/line.rs:18) const MAX_LINE_AUDIO_BYTES: u64 = 25 * 1024 * 1024; // after (raises the in-memory cap; whole body is still buffered) const MAX_LINE_AUDIO_BYTES: u64 = 50 * 1024 * 1024;
Defensive patterns
Strategy: validation
Validate before calling
// Reject oversized content before buffering any of it
if let Some(len) = resp.content_length() {
anyhow::ensure!(
len <= MAX_LINE_AUDIO_BYTES,
"line audio content-length {len} over cap; skipping download for {message_id}"
);
} Type guard
fn is_audio_size_error(err: &anyhow::Error) -> bool {
err.to_string().contains("audio exceeds")
} Try / catch
if is_audio_size_error(&e) {
tracing::warn!(error = %e, "oversized line audio; skipping transcription");
return Ok(());
} Prevention
- Pre-check Content-Length on media downloads.
- Isolate transcription failures from message acknowledgement.
- Size memory for the cap you compile in.
When it happens
Trigger: An inbound LINE audio message whose content exceeds 25 MiB: long voice messages, high-bitrate audio files, or content-type changes reclassifying large media as audio.
Common situations: Long forwarded voice notes, users attaching recorded audio files, or test fixtures with oversized payloads.
Related errors
- audio download exceeds {} byte limit
- audio download failed ({status}) for message {message_id}
- Audio file too large ({} bytes, max {MAX_AUDIO_BYTES})
- Audio file too large ({} bytes, global max {})
- plugin archive exceeds maximum size of {max_bytes} bytes
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/612115c703e982cf.
Report an issue: GitHub.