{"record":{"id":"ef757202b0b8c613","repo":"tonhowtf/omniget","slug":"zip-invalido-github","errorCode":null,"errorMessage":"zip invalido: {}","messagePattern":"zip invalido: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/github.rs","lineNumber":117,"sourceCode":"                \"[tools] {} veio sem digest; aceito sem verificacao\",\n                asset.name\n            )\n        }\n        None => {\n            return Err(anyhow!(\n                \"{} veio sem digest da API do GitHub; download descartado\",\n                asset.name\n            ))\n        }\n    }\n    Ok(bytes)\n}\n\npub fn unpack(data: &[u8], name: &str, dest: &Path) -> anyhow::Result<()> {\n    std::fs::create_dir_all(dest)?;\n    if name.ends_with(\".zip\") {\n        let mut archive = zip::ZipArchive::new(std::io::Cursor::new(data))\n            .map_err(|e| anyhow!(\"zip invalido: {}\", e))?;\n        for i in 0..archive.len() {\n            let mut file = archive.by_index(i)?;\n            let Some(rel) = file.enclosed_name() else {\n                continue;\n            };\n            let out = dest.join(rel);\n            if file.is_dir() {\n                std::fs::create_dir_all(&out)?;\n                continue;\n            }\n            if let Some(parent) = out.parent() {\n                std::fs::create_dir_all(parent)?;\n            }\n            let mut w = std::fs::File::create(&out)?;\n            std::io::copy(&mut file, &mut w)?;\n        }\n        Ok(())\n    } else if name.ends_with(\".tar.gz\") || name.ends_with(\".tgz\") {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/github.rs#L99-L135","documentation":"unpack() extracts downloaded GitHub release archives. For names ending in .zip it opens the bytes with zip::ZipArchive; any parse/open failure (corrupt download, truncated file, non-zip data) is wrapped as 'zip invalido: {}'.","triggerScenarios":"Calling unpack(data, name, dest) where name ends with .zip but data is not a valid zip: truncated/incomplete download, HTML error page saved as bytes, corrupted transfer.","commonSituations":"Network interruption mid-download stored as the final file; proxy/captive portal returning an HTML page; asset uploaded incorrectly to the release.","solutions":["Re-download the asset and verify its digest before unpacking (github::download enforces this)","Check the first bytes are 'PK' (zip magic) to confirm the payload is actually a zip","Read the wrapped inner error 'e' in the message for the specific zip failure (e.g. InvalidArchive, UnsupportedArchive)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn looks_like_zip(data: &[u8]) -> bool {\n    data.starts_with(b\"PK\")\n}\nif !looks_like_zip(&data) {\n    return Err(\"payload nao e um zip; baixe novamente e verifique o digest\".into());\n}\ngithub::unpack(&data, name, &dest)?;","typeGuard":null,"tryCatchPattern":"match github::unpack(&data, name, &dest) {\n    Err(e) if e.to_string().starts_with(\"zip invalido\") => {\n        eprintln!(\"arquivo corrompido; refazendo download...\");\n        let data = github::download(&asset).await?;\n        github::unpack(&data, name, &dest)?;\n    }\n    other => other?,\n}","preventionTips":["Verify the asset digest (github::download already does) before unpacking","Check zip magic bytes 'PK' as a cheap pre-check","Clean up partially written downloads on error so retries start fresh"],"tags":["github","zip","archive"],"backgroundTag":"file-read-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}