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

  1. Treat as expected degradation: skip transcription for oversized audio and optionally notify the user.
  2. If larger audio must be supported, raise const MAX_LINE_AUDIO_BYTES in crates/zeroclaw-channels/src/line.rs and rebuild, accounting for memory.
  3. 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

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


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/612115c703e982cf. Report an issue: GitHub.