{"record":{"id":"612115c703e982cf","repo":"zeroclaw-labs/zeroclaw","slug":"audio-exceeds-byte-limit-for-message-message-i","errorCode":null,"errorMessage":"audio exceeds {} byte limit for message {message_id}","messagePattern":"audio exceeds (.+?) byte limit for message (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-channels/src/line.rs","lineNumber":208,"sourceCode":") -> anyhow::Result<Vec<u8>> {\n    let url = format!(\"{content_api_base_url}/v2/bot/message/{message_id}/content\");\n    let resp = client\n        .get(&url)\n        .bearer_auth(channel_access_token)\n        .send()\n        .await?;\n\n    if !resp.status().is_success() {\n        let status = resp.status();\n        anyhow::bail!(\"audio download failed ({status}) for message {message_id}\");\n    }\n\n    let mut bytes = Vec::new();\n    let mut stream = resp;\n    while let Some(chunk) = stream.chunk().await? {\n        bytes.extend_from_slice(&chunk);\n        if bytes.len() as u64 > MAX_LINE_AUDIO_BYTES {\n            anyhow::bail!(\n                \"audio exceeds {} byte limit for message {message_id}\",\n                MAX_LINE_AUDIO_BYTES\n            );\n        }\n    }\n    Ok(bytes)\n}\n\nfn build_webhook_router(state: Arc<LineState>) -> axum::Router {\n    use axum::{Router, routing::post};\n    Router::new()\n        .route(\"/line/webhook\", post(handle_webhook))\n        .with_state(state)\n}\n\n/// Check whether `user_id` is in the LINE peer allowlist resolved from\n/// canonical config state at call-time. LINE user IDs are case-sensitive.\nfn is_line_user_allowed(state: &LineState, user_id: &str) -> bool {","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/line.rs#L190-L226","documentation":"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.","triggerScenarios":"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.","commonSituations":"Long forwarded voice notes, users attaching recorded audio files, or test fixtures with oversized payloads.","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."],"exampleFix":"// before (crates/zeroclaw-channels/src/line.rs:18)\nconst MAX_LINE_AUDIO_BYTES: u64 = 25 * 1024 * 1024;\n\n// after (raises the in-memory cap; whole body is still buffered)\nconst MAX_LINE_AUDIO_BYTES: u64 = 50 * 1024 * 1024;","handlingStrategy":"validation","validationCode":"// Reject oversized content before buffering any of it\nif let Some(len) = resp.content_length() {\n    anyhow::ensure!(\n        len <= MAX_LINE_AUDIO_BYTES,\n        \"line audio content-length {len} over cap; skipping download for {message_id}\"\n    );\n}","typeGuard":"fn is_audio_size_error(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"audio exceeds\")\n}","tryCatchPattern":"if is_audio_size_error(&e) {\n    tracing::warn!(error = %e, \"oversized line audio; skipping transcription\");\n    return Ok(());\n}","preventionTips":["Pre-check Content-Length on media downloads.","Isolate transcription failures from message acknowledgement.","Size memory for the cap you compile in."],"tags":["line","audio","size-limit","streaming","transcription"],"backgroundTag":"download-size-limit-exceeded","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}