tonhowtf/omniget · error · anyhow::Error

Failed to read tar entries

Error message

Failed to read tar entries: {}

What it means

After opening the .tar.xz and wrapping it in an xz2 XzDecoder and tar::Archive, extract_tar_xz_ffmpeg calls archive.entries() to iterate members. Failure here means the tar iterator could not be created/started - typically the underlying stream is not a valid tar, or the xz stream is corrupt/truncated.

Solutions

  1. Delete and re-download the archive; verify integrity (size/checksum) before extraction
  2. Verify the file magic bytes: FD 37 7A 58 5A 00 for xz, and gzip's 1F 8B if the upstream switched formats
  3. Use the matching decoder (GzDecoder vs XzDecoder) for the actual format
  4. Check that the download response status was success and Content-Length matched

Example fix

// before
let decompressor = xz2::read::XzDecoder::new(file);
// after
let mut magic = [0u8; 6];
let mut peek = std::fs::File::open(&archive_path)?;
use std::io::Read;
peek.read_exact(&mut magic)?;
if &magic != b"\xfd7zXZ\x00" {
    return Err(anyhow!("Downloaded artifact is not an xz archive; re-download or switch decoder"));
}
let decompressor = xz2::read::XzDecoder::new(peek);
Defensive patterns

Strategy: validation

Validate before calling

let mut f = std::fs::File::open(&archive_path)?;
let mut magic = [0u8; 6];
std::io::Read::read_exact(&mut f, &mut magic)?;
if &magic != b"\xfd7zXZ\x00" {
    return Err(anyhow!("artifact is not xz; check upstream format"));
}

Type guard

fn is_xz_file(p: &std::path::Path) -> bool {
    use std::io::Read;
    std::fs::File::open(p).map(|mut f| {
        let mut m = [0u8; 6];
        f.read_exact(&mut m).is_ok() && &m == b"\xfd7zXZ\x00"
    }).unwrap_or(false)
}

Try / catch

match extract_tar_xz_ffmpeg(&path, &bin_dir, &ff, &fprobe).await {
    Err(e) if e.to_string().contains("Failed to read tar entries") => {
        // format mismatch or corruption: detect magic, re-download with correct decoder
        std::fs::remove_file(&path).ok();
        download_ffmpeg(...).await?;
    },
    r => r?,
}

Prevention

When it happens

Trigger: The downloaded file is not actually xz-compressed tar (e.g. gzip tar or plain HTML error page), the xz stream is truncated mid-download, or the tar header block is invalid.

Common situations: Upstream changed the artifact from .tar.xz to .tar.gz but the extractor was not updated; proxy returned an error page saved with a .tar.xz name; incomplete download on flaky network.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/d33a3b1fc82f5391. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/dependencies.rs:634

    bin_dir: &std::path::Path,
    ffmpeg_name: &str,
    ffprobe_name: &str,
) -> anyhow::Result<()> {
    let archive_path = archive_path.to_path_buf();
    let bin_dir = bin_dir.to_path_buf();
    let ffmpeg_name = ffmpeg_name.to_string();
    let ffprobe_name = ffprobe_name.to_string();

    tokio::task::spawn_blocking(move || {
        let file = std::fs::File::open(&archive_path)
            .map_err(|e| anyhow!("Failed to open archive: {}", e))?;
        let decompressor = xz2::read::XzDecoder::new(file);
        let mut archive = tar::Archive::new(decompressor);
        let targets = [ffmpeg_name.as_str(), ffprobe_name.as_str()];

        for entry_result in archive
            .entries()
            .map_err(|e| anyhow!("Failed to read tar entries: {}", e))?
        {
            let mut entry = entry_result.map_err(|e| anyhow!("Failed to read tar entry: {}", e))?;
            let path = entry
                .path()
                .map_err(|e| anyhow!("Failed to read entry path: {}", e))?;
            let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
            for target in &targets {
                if file_name == *target {
                    let dest = bin_dir.join(format!("{}.new", target));
                    let mut out = std::fs::File::create(&dest)?;
                    std::io::copy(&mut entry, &mut out)?;
                    break;
                }
            }
        }
        Ok::<(), anyhow::Error>(())
    })
    .await

View on GitHub (pinned to 8600b91f42)