rust-lang/cargo · critical · anyhow::Error

invalid tarball downloaded, contains a file at {entry_path:?

Error message

invalid tarball downloaded, contains a file at {entry_path:?} which isn't under {prefix:?}

What it means

While unpacking a downloaded `.crate` tarball (src/sources/registry/mod.rs:977), Cargo requires every archive entry's path to live under the expected package prefix (`<name>-<version>/`). An entry that doesn't `strip_prefix(prefix)` is rejected as an invalid/malicious tarball — this is the path-traversal / wrong-packaging guard. The comment notes Cargo itself and crates.io should never produce such tarballs; this check is a belt-and-suspenders defense.

Source

Thrown at src/sources/registry/mod.rs:988

    for entry in tar.entries()? {
        let mut entry = entry.context("failed to iterate over archive")?;
        let entry_path = entry
            .path()
            .context("failed to read entry path")?
            .into_owned();

        if let Ok(path) = entry_path.strip_prefix(prefix) {
            if !include(path) {
                continue;
            }
        } else {
            // We're going to unpack this tarball into the global source
            // directory, but we want to make sure that it doesn't accidentally
            // (or maliciously) overwrite source code from other crates. Cargo
            // itself should never generate a tarball that hits this error, and
            // crates.io should also block uploads with these sorts of tarballs,
            // but be extra sure by adding a check here as well.
            anyhow::bail!(
                "invalid tarball downloaded, contains \
                     a file at {entry_path:?} which isn't under {prefix:?}",
            )
        }

        // Prevent unpacking symlinks and other unexpected entry types
        match entry.header().entry_type() {
            EntryType::Regular | EntryType::Directory => {}
            t => anyhow::bail!(
                "invalid tarball downloaded, contains an entry at {entry_path:?} with invalid type {t:?}",
            ),
        }

        // Prevent unpacking the lockfile from the crate itself.
        if entry_path
            .file_name()
            .map_or(false, |p| p == PACKAGE_SOURCE_LOCK)
        {

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Re-create/re-download the tarball: clear `~/.cargo/registry/cache/<reg>/<pkg>-<ver>.crate` and refetch.
  2. If you publish/maintain the crate, ensure your packaging produces entries under `<name>-<version>/` (standard `cargo package` output).
  3. Inspect the tarball manually (`tar -tvf <file>.crate`) to see the offending entry path and fix the upstream packaging.
  4. Treat as a potential supply-chain attack if the registry is untrusted — stop using that registry.
Defensive patterns

Strategy: validation

Validate before calling

// Validate a tarball before unpacking: every entry must live under the prefix.
fn tarball_has_valid_prefix<R: Read>(tar: &mut tar::Archive<R>, prefix: &str) -> bool {
    for e in tar.entries().ok().into_iter().flatten() {
        if !e.path().ok().map_or(false, |p| p.starts_with(prefix)) { return false; }
    }
    true
}

Type guard

pub fn entry_under_prefix(p: &std::path::Path, prefix: &str) -> bool {
    p.strip_prefix(prefix).is_ok()
}

Prevention

When it happens

Trigger: A tarball containing an entry whose path doesn't start with `<name>-<version>/` — e.g. an absolute path (`/etc/...`), a `../` traversal, or a flat entry with no prefix. Produced by a buggy custom registry/packaging tool, a corrupted download, or an attacker-controlled tarball.

Common situations: A private registry whose packaging tool doesn't prepend the `name-version/` prefix; a corrupted/garbled download that scrambled entry paths; a malicious substitute registry. Should never happen for crates.io-published crates.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/c0662a46180a7ac3.json. Report an issue: GitHub.