zeroclaw-labs/zeroclaw · error · anyhow::Error
plugin archive exceeds maximum size of {max_bytes} bytes
Error message
plugin archive exceeds maximum size of {max_bytes} bytes What it means
The streaming backstop of the archive size cap: while reading the response body chunk by chunk, append_chunk_capped bails as soon as accumulated bytes (plus the incoming chunk) would exceed max_bytes. It catches servers that lie about (or omit) Content-Length, which the header check (error 1409) cannot see.
Source
Thrown at src/plugin_registry.rs:144
}
Ok(bytes)
}
pub(crate) fn collect_capped_chunks<I>(chunks: I, max_bytes: usize) -> Result<Vec<u8>>
where
I: IntoIterator<Item = Result<Vec<u8>>>,
{
let mut bytes = Vec::new();
for chunk in chunks {
let chunk = chunk?;
append_chunk_capped(&mut bytes, &chunk, max_bytes)?;
}
Ok(bytes)
}
fn append_chunk_capped(bytes: &mut Vec<u8>, chunk: &[u8], max_bytes: usize) -> Result<()> {
if bytes.len().saturating_add(chunk.len()) > max_bytes {
bail!("plugin archive exceeds maximum size of {max_bytes} bytes");
}
bytes.extend_from_slice(chunk);
Ok(())
}
fn verify_sha256_if_present(bytes: &[u8], expected: Option<&str>) -> Result<()> {
let Some(expected) = expected else {
return Ok(());
};
let expected = expected.strip_prefix("sha256:").unwrap_or(expected);
let actual = hex::encode(Sha256::digest(bytes));
if !actual.eq_ignore_ascii_case(expected) {
bail!("plugin archive sha256 mismatch");
}
Ok(())
}
pub(crate) fn extract_zip_safe<R>(reader: R, dest: &Path) -> Result<PathBuf>View on GitHub (pinned to 88bb9c8533)
Solutions
- Treat it as the cap working as designed: the remote is sending more bytes than it declared (or nothing at all)
- Fetch the URL manually (curl -L <url> -o /dev/null -w '%{size_download}') to see the true size
- Re-publish a smaller artifact, or point the entry at a host that reports accurate Content-Length so the header check can fail fast
- Raise the limit only if the artifact legitimately needs to be larger and you accept the memory implications
Example fix
# before: server sends chunked body of 2x the cap with no Content-Length # after: serve the artifact with an accurate header curl -I https://cdn/p.zip # must show content-length < MAX_PLUGIN_ZIP_BYTES
Defensive patterns
Strategy: try-catch
Try / catch
// Stream the body yourself with the same saturating cap if you need custom UX:
let mut total = 0usize;
while let Some(chunk) = resp.chunk().await? {
total = total.saturating_add(chunk.len());
if total > MAX_PLUGIN_ZIP_BYTES { return Err(anyhow::anyhow!("over cap")); }
buf.extend_from_slice(&chunk);
} Prevention
- Serve artifacts from hosts that report accurate Content-Length
- Never retry an over-cap download unchanged — it will fail again
- Treat repeated header/stream cap disagreement as a tampering signal
When it happens
Trigger: Downloading a plugin archive where Content-Length is missing or understated, and the actual streamed body exceeds MAX_PLUGIN_ZIP_BYTES. Reached from download_archive_bytes' chunk loop (and reusable via collect_capped_chunks).
Common situations: Chunked transfer-encoding with no Content-Length from the artifact host; a proxy/CDN rewriting headers; a malicious or misconfigured server deliberately under-reporting size to slip a large payload through.
Related errors
- plugin archive exceeds maximum size of {MAX_PLUGIN_ZIP_BYTES
- plugin archive exceeds extracted size limit of {max_extracte
- audio download exceeds {} byte limit
- audio exceeds {} byte limit for message {message_id}
- plugin archive sha256 mismatch
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/8893b3583b4af0da.
Report an issue: GitHub.