{"record":{"id":"3eb278316d3e42ee","repo":"Hmbown/CodeWhale","slug":"download-url-exceeds-compressed-size-cap-of-com","errorCode":null,"errorMessage":"download {url} exceeds compressed size cap of {compressed_cap} bytes","messagePattern":"download (.+?) exceeds compressed size cap of (.+?) bytes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/skills/install.rs","lineNumber":1166,"sourceCode":"        .send()\n        .await\n        .with_context(|| format!(\"failed to GET {url}\"))?;\n    let status = resp.status();\n    if !status.is_success() {\n        if status == reqwest::StatusCode::NOT_FOUND {\n            return Ok(DownloadAttempt::NotFound(status));\n        }\n        bail!(\"download {url} returned {status}\");\n    }\n    // Soft cap on the *compressed* download — well above max_size to allow\n    // for highly compressible payloads but still bounded.\n    let compressed_cap = max_size.saturating_mul(4);\n    let bytes = resp\n        .bytes()\n        .await\n        .with_context(|| format!(\"failed to read body of {url}\"))?;\n    if (bytes.len() as u64) > compressed_cap {\n        bail!(\"download {url} exceeds compressed size cap of {compressed_cap} bytes\");\n    }\n    Ok(DownloadAttempt::Bytes(bytes.to_vec()))\n}\n\nstruct StagedSkill {\n    skill_name: String,\n    staged_path: PathBuf,\n}\n\n/// Validate a tarball and extract it into `<skills_dir>/<name>.tmp/`.\nfn stage_tarball(bytes: &[u8], skills_dir: &Path, max_size: u64) -> Result<StagedSkill> {\n    fs::create_dir_all(skills_dir)\n        .with_context(|| format!(\"failed to create skills directory {}\", skills_dir.display()))?;\n\n    // Two passes: first determine the skill name (and therefore the staged\n    // dir) by finding the SKILL.md, then extract under that staged dir.\n    // Both passes share the same archive bytes; we reset by wrapping fresh\n    // decoders.","sourceCodeStart":1148,"sourceCodeEnd":1184,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/skills/install.rs#L1148-L1184","documentation":"download_with_cap enforces a soft compressed-size cap of 4x the configured max_size on the bytes actually read; the unpack step separately enforces max_size on uncompressed bytes. A body over the cap bails with the limit in the message. The cap exists to bound memory before decompressing payloads that could expand enormously.","triggerScenarios":"Installing a skill tarball whose compressed size exceeds 4x the configured skill size limit (e.g. a 10 MiB limit rejecting anything above ~40 MiB compressed), or a misdirected URL serving a huge file such as a full repo archive with vendored dependencies.","commonSituations":"Community skills bundling binaries or media, monorepo archives grabbed whole by the github: shorthand, and locally lowered limits on constrained machines.","solutions":["Raise the skill max-size configuration if the artifact is legitimately large.","Point the install at a slimmer artifact: a release tarball or subpath export rather than the full repo archive.","If the size is unexpected, inspect the URL; a redirect to an HTML page or wrong artifact can inflate it.","Report oversized skills upstream so the canonical artifact stays under limits."],"exampleFix":"# before: limit 10 MiB, artifact 45 MiB compressed\n/skill install github:owner/big-repo\n\n# after: install the slim release tarball\n/skill install https://github.com/owner/big-repo/releases/download/v1/pack.tar.gz","handlingStrategy":"fallback","validationCode":"// HEAD pre-check against the same 4x compressed cap used at download time\nlet resp = reqwest_client().head(url).send().await?;\nif let Some(len) = resp\n    .headers()\n    .get(reqwest::header::CONTENT_LENGTH)\n    .and_then(|v| v.to_str().ok())\n    .and_then(|v| v.parse::<u64>().ok())\n{\n    if len > max_size.saturating_mul(4) {\n        eprintln!(\"artifact is {len} bytes, above the compressed cap; pick a slimmer source\");\n    }\n}","typeGuard":null,"tryCatchPattern":"match fetch_tarball(&source, &network, max_size).await {\n    Err(err) if err.to_string().contains(\"exceeds compressed size cap\") => {\n        // fallback: install a slimmer release artifact or raise the configured limit\n    }\n    other => other?,\n}","preventionTips":["Install release tarballs or subpath exports for large repos instead of whole-repo archives.","Set the skill size limit deliberately; the compressed cap is 4x that value.","Treat surprise size failures as a wrong-URL signal and inspect what is actually served."],"tags":["skills","download","size-limit","security","rust"],"backgroundTag":"download-size-limit-exceeded","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}