Hmbown/CodeWhale · error
download exceeds compressed size cap of bytes
Error message
download {url} exceeds compressed size cap of {compressed_cap} bytes What it means
`download_with_cap` enforces a soft cap on the compressed body of `max_size * 4` bytes before decompression, bounding memory use. A response larger than this cap is rejected rather than fully buffered, even if it would decompress under `max_size`.
Solutions
- Increase the `max_size` argument so the compressed cap (4x) accommodates the payload
- Publish/download a smaller, compressed (gzip) tarball of the skill
- Host the skill in smaller components and install them separately
Example fix
// before let MAX: u64 = 1 * 1024 * 1024; // cap 4 MiB, payload is 6 MiB compressed // after let MAX: u64 = 4 * 1024 * 1024; // cap 16 MiB
Defensive patterns
Strategy: validation
Validate before calling
if expected_compressed_bytes > max_size * 4 {
return Err(anyhow!("payload exceeds compressed cap; raise max_size"));
} Prevention
- Set max_size to cover the largest expected compressed payload
- Keep published skill tarballs small and gzip-compressed
- Check Content-Length before download when available
When it happens
Trigger: Downloading a skill tarball whose compressed body exceeds `4 * max_size` bytes — very large archives, or a small `max_size` argument relative to the payload.
Common situations: Registry entry pointing at a huge archive; caller passing an artificially low `max_size`; mirrors serving uncompressed (already-large) tarballs; a compromised/hostile URL serving gigabytes.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- payload exceeds bytes
- private lane environment exceeds
- bounded provider catalog cache exceeds its write limit
- bundle at is bytes; the limit is bytes
- Checksum mismatch for
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/3eb278316d3e42ee.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/skills/install.rs:1169
.send()
.await
.with_context(|| format!("failed to GET {url}"))?;
let status = resp.status();
if !status.is_success() {
if status == reqwest::StatusCode::NOT_FOUND {
return Ok(DownloadAttempt::NotFound(status));
}
bail!("download {url} returned {status}");
}
// Soft cap on the *compressed* download — well above max_size to allow
// for highly compressible payloads but still bounded.
let compressed_cap = max_size.saturating_mul(4);
let bytes = resp
.bytes()
.await
.with_context(|| format!("failed to read body of {url}"))?;
if (bytes.len() as u64) > compressed_cap {
bail!("download {url} exceeds compressed size cap of {compressed_cap} bytes");
}
Ok(DownloadAttempt::Bytes(bytes.to_vec()))
}
struct StagedSkill {
skill_name: String,
staged_path: PathBuf,
}
/// Validate a tarball and extract it into `<skills_dir>/<name>.tmp/`.
fn stage_tarball(bytes: &[u8], skills_dir: &Path, max_size: u64) -> Result<StagedSkill> {
fs::create_dir_all(skills_dir)
.with_context(|| format!("failed to create skills directory {}", skills_dir.display()))?;
// Two passes: first determine the skill name (and therefore the staged
// dir) by finding the SKILL.md, then extract under that staged dir.
// Both passes share the same archive bytes; we reset by wrapping fresh
// decoders.View on GitHub (pinned to 73e0f67d83)