tonhowtf/omniget · critical · anyhow::Error
: hash nao confere — esperado , obtido . Download…
Error message
{}: hash nao confere — esperado {}, obtido {}. Download descartado. What it means
verify_sha256 computes the SHA-256 of the downloaded bytes and compares it to the expected lowercase hex digest. On mismatch it discards the download and throws an error naming the label, expected hash, and actual hash. This integrity guard prevents running tampered or corrupt binaries.
Solutions
- Compare expected vs actual hashes in the message: if the upstream release changed, update the pinned expected hash from the official release source.
- Re-download the file and verify again — transient corruption/truncation is fixed by a fresh download.
- Confirm the hash comes from a trusted channel (official release notes over HTTPS, not a mirror).
- If the mismatch persists with a trusted hash, treat the source as compromised: do not execute the binary and investigate the network path.
Example fix
// before
let bytes = download(url).await?;
verify_sha256(&bytes, EXPECTED_HASH, "recusa-binario")?;
// after
let bytes = download(url).await?;
if let Err(e) = verify_sha256(&bytes, EXPECTED_HASH, "recusa-binario") {
tracing::warn!("hash mismatch, re-downloading once: {}", e);
let bytes = download(url).await?;
verify_sha256(&bytes, EXPECTED_HASH, "recusa-binario")?;
} Defensive patterns
Strategy: validation
Validate before calling
fn sha256_matches(bytes: &[u8], expected: &str) -> bool {
let actual = sha256_hex(bytes);
actual == expected.to_lowercase()
}
// call before executing/using any downloaded binary
if !sha256_matches(&bytes, EXPECTED_HASH) {
eprintln!("Integrity check failed — discard download, do not execute");
} Type guard
fn is_valid_hex_sha256(s: &str) -> bool {
s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit())
} Try / catch
match verify_sha256(&bytes, expected, label) {
Err(e) => {
// Never fall back to executing unverified bytes
tracing::error!("discarding download: {}", e);
std::fs::remove_file(temp_path)?;
return Err(e);
}
Ok(()) => { /* safe to proceed */ }
} Prevention
- Always pin hashes from official HTTPS release channels
- Re-download once on mismatch to rule out transient corruption
- Never execute binaries that fail the integrity check
- Update pinned hashes promptly when upstream releases new builds
- Normalize expected hashes to lowercase before comparing
When it happens
Trigger: Calling verify_sha256 with bytes whose actual SHA-256 does not equal the expected hex string (case-insensitively) — e.g. the binary published upstream changed after the expected hash was pinned, the download was truncated/corrupted, or a proxy/CDN served different content.
Common situations: Upstream released a new build without updating the pinned hash; interrupted or proxied download corrupting bytes; MITM or supply-chain tampering (the exact scenario this check defends against); wrong hash string copied from release notes.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- yt-dlp: verificacao de integridade impossivel
- o pacote do ONNX Runtime baixado não confere: esperava…
- veio sem digest da API do GitHub; download descartado
- veio sem digest da API do GitHub; download descartado
- o modelo baixado não confere: esperava sha256
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/485b38f7783a879f.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/dependencies.rs:71
/// Arquivo `.sha256sum` de asset único (o Deno publica um por asset).
pub fn parse_single_sha256(text: &str) -> Option<String> {
let first = text.split_whitespace().next()?;
is_sha256(first).then(|| first.to_lowercase())
}
/// `digest` da API de releases do GitHub, no formato `sha256:<hex>`.
pub fn parse_github_digest(digest: &str) -> Option<String> {
let hex = digest.trim().strip_prefix("sha256:")?;
is_sha256(hex).then(|| hex.to_lowercase())
}
pub fn verify_sha256(bytes: &[u8], expected: &str, label: &str) -> anyhow::Result<()> {
let actual = sha256_hex(bytes);
if actual == expected.to_lowercase() {
tracing::info!("[integrity] {} verificado (sha256 confere)", label);
return Ok(());
}
Err(anyhow!(
"{}: hash nao confere — esperado {}, obtido {}. Download descartado.",
label,
expected,
actual
))
}
/// Busca o hash esperado num arquivo de sums remoto. `Err` quando a origem
/// publica sums mas não conseguimos obtê-los — o chamador deve abortar.
pub async fn expected_from_sums_url(
client: &reqwest::Client,
sums_url: &str,
asset: &str,
) -> anyhow::Result<String> {
let response = client
.get(sums_url)
.send()
.awaitView on GitHub (pinned to 8600b91f42)