rust-lang/cargo · error

failed to verify the checksum of

Error message

failed to verify the checksum of `{}`

What it means

After downloading a `.crate` tarball from a registry, Cargo computes `SHA256(data)` and compares it to the checksum recorded in the registry index / lockfile. A mismatch means the downloaded bytes differ from what the registry attests — indicating corruption, a man-in-the-middle, a stale mirror, or a tampered cache. The error names the package id that failed.

Solutions

  1. Clear the cached tarball: `cargo cache --autoclean` or remove `~/.cargo/registry/cache/<index>/<pkg>-<ver>.crate`, then re-run.
  2. Re-fetch the index: `rm -rf ~/.cargo/registry/index/<index>` and `cargo fetch`, to rule out a stale index.
  3. Switch off or update the registry mirror/proxy that may be serving a mismatched tarball.
  4. Verify network integrity (retry on a stable connection, disable aggressive VPN/proxy caching).

Example fix

# before: download corrupted/mismatched
$ cargo build
error: failed to verify the checksum of `serde v1.0.0`

# after: clear and refetch
$ rm -rf ~/.cargo/registry/cache/index.crates.io-*/serde-1.0.0.crate
$ cargo fetch && cargo build
Defensive patterns

Strategy: retry

Validate before calling

// Before trusting a downloaded tarball, recompute and compare.
fn verify_crate_sha256(path: &Path, expected: &str) -> Result<(), anyhow::Error> {
    let data = std::fs::read(path)?;
    use sha2::{Digest, Sha256};
    let mut h = Sha256::new(); h.update(&data);
    let got = hex::encode(h.finalize());
    if got != expected { anyhow::bail!("checksum mismatch for {}: got {}", path.display(), got); }
    Ok(())
}

Type guard

fn checksum_matches(path: &std::path::Path, expected: &str) -> bool {
    std::fs::read(path).ok().map(|d| {
        use sha2::{Digest, Sha256}; let mut h = Sha256::new(); h.update(&d);
        hex::encode(h.finalize()) == expected
    }).unwrap_or(false)
}

Try / catch

for attempt in 0..3 {
    match registry.finish_download(...) {
        Ok(f) => return Ok(f),
        Err(e) if e.to_string().contains("checksum") && attempt < 2 => {
            let _ = std::fs::remove_file(&crate_path); // retry after clearing
            continue;
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: `finish_download` in `src/sources/registry/download.rs` is called after the HTTP fetch completes; the computed SHA-256 of `data` does not equal the `checksum` argument passed in. Triggered by truncated downloads, proxy corruption, disk errors, registry mirror skew, or an out-of-date index pointing at a replaced tarball.

Common situations: Flaky network/proxy truncating the tarball; a corporate mirror whose cached `.crate` was replaced but whose index was not updated; concurrent processes writing into `~/.cargo/registry/cache`; disk/full-filesystem partial writes; clock-skewed or partially-synced registry mirrors.

Related errors


AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11). Data as JSON: /api/errors/8f8e92b95703d662. Report an issue: GitHub.

Appendix: source

Thrown at src/sources/registry/download.rs:102

    })
}

/// Verifies the integrity of `data` with `checksum` and persists it under the
/// directory at `cache_path`.
///
/// This is primarily called by [`RegistryData::finish_download`](super::RegistryData::finish_download).
pub(super) fn finish_download(
    cache_path: &Filesystem,
    gctx: &GlobalContext,
    encoded_registry_name: InternedString,
    pkg: PackageId,
    checksum: &str,
    data: &[u8],
) -> CargoResult<File> {
    // Verify what we just downloaded
    let actual = Sha256::new().update(data).finish_hex();
    if actual != checksum {
        anyhow::bail!("failed to verify the checksum of `{}`", pkg)
    }
    gctx.deferred_global_last_use()?.mark_registry_crate_used(
        global_cache_tracker::RegistryCrate {
            encoded_registry_name,
            crate_filename: pkg.tarball_name().into(),
            size: data.len() as u64,
        },
    );

    cache_path.create_dir()?;
    let path = cache_path.join(&pkg.tarball_name());
    let path = gctx.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
    let mut dst = OpenOptions::new()
        .create(true)
        .read(true)
        .write(true)
        .open(&path)
        .with_context(|| format!("failed to open `{}`", path.display()))?;

View on GitHub (pinned to eb98b54bc9)