rust-lang/rust · error

tarball extension not recognized

Error message

tarball extension not recognized: {}

What it means

In src/tools/build-manifest/src/versions.rs the tarball reader only recognizes .gz (GzDecoder) and .xz (XzDecoder) extensions. Any other extension (or no extension) falls through to unimplemented!("tarball extension not recognized: {}") at versions.rs:255.

Solutions

  1. Ensure the input tarball uses .tar.gz or .tar.xz compression.
  2. Recompress the artifact: e.g. 'zstd -d f.tar.zst && gzip f.tar' to produce a .gz build-manifest can read.
  3. Extend build-manifest to add a zstd/bzip2 branch if your release now ships those formats.
  4. Check for a missing/empty extension (e.g. a directory passed instead of a tarball).

Example fix

// before
let tar = Archive::new(/* extension is .zst -> panic */);

// after: add zstd support
use zstd::Decoder;
let decoder = if ext == "zst" { Box::new(Decoder::new(file)?) } else { /* gz/xz */ };
Defensive patterns

Strategy: validation

Validate before calling

fn is_supported_tarball(path: &Path) -> bool {
    matches!(path.extension().and_then(|e| e.to_str()), Some("gz") | Some("xz"))
}
// Only pass tarballs where is_supported_tarball returns true to the version reader.

Prevention

When it happens

Trigger: Running build-manifest to extract version/git-commit files from a release tarball whose name does not end in .tar.gz or .tar.xz — e.g. a .tar.zst, .tar.bz2, a plain .tar, or a misnamed file.

Common situations: Release pipeline producing .zst tarballs; a manually renamed artifact; a dist that changed compression format without updating build-manifest.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/1675ba0adbaa9a11. Report an issue: GitHub.

Appendix: source

Thrown at src/tools/build-manifest/src/versions.rs:255

    }

    fn load_version_from_tarball_inner(&mut self, tarball: &Path) -> Result<VersionInfo, Error> {
        let file = match File::open(&tarball) {
            Ok(file) => file,
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
                // Missing tarballs do not return an error, but return empty data.
                println!("warning: missing tarball {}", tarball.display());
                return Ok(VersionInfo::default());
            }
            Err(err) => return Err(err.into()),
        };
        let mut tar: Archive<Box<dyn std::io::Read>> =
            Archive::new(if tarball.extension().map_or(false, |e| e == "gz") {
                Box::new(GzDecoder::new(file))
            } else if tarball.extension().map_or(false, |e| e == "xz") {
                Box::new(XzDecoder::new(file))
            } else {
                unimplemented!("tarball extension not recognized: {}", tarball.display())
            });

        let mut version = None;
        let mut git_commit = None;
        for entry in tar.entries()? {
            let mut entry = entry?;

            let dest;
            match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
                Some("version") => dest = &mut version,
                Some("git-commit-hash") => dest = &mut git_commit,
                _ => continue,
            }
            let mut buf = String::new();
            entry.read_to_string(&mut buf)?;
            *dest = Some(buf);

            // Short circuit to avoid reading the whole tar file if not necessary.

View on GitHub (pinned to 7088e4b63a)