dotnet/efcore · error · FileNotFoundError

Could not find 'data.tar.*' in {deb_file}.

Error message

Could not find 'data.tar.*' in {deb_file}.

What it means

Raised as FileNotFoundError by extract_deb_file after `ar t <deb>` lists the archive members and none of them starts with 'data.tar'. Every valid .deb contains debian-binary, control.tar.*, and data.tar.*; absence of data.tar.* means the payload member is missing - the file is truncated, empty, or not actually a .deb (e.g. an HTML error page the mirror served with status 200).

Source

Thrown at eng/common/cross/install-debs.py:308

    print("All done!")

def extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool):
    """Extract .deb file contents"""

    os.makedirs(extract_dir, exist_ok=True)

    with tempfile.TemporaryDirectory(dir=tmp_dir) as tmp_subdir:
        result = subprocess.run([ar_tool, "t", os.path.abspath(deb_file)], cwd=tmp_subdir, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        tar_filename = None
        for line in result.stdout.decode().splitlines():
            if line.startswith("data.tar"):
                tar_filename = line.strip()
                break

        if not tar_filename:
            raise FileNotFoundError(f"Could not find 'data.tar.*' in {deb_file}.")

        tar_file_path = os.path.join(tmp_subdir, tar_filename)
        print(f"Extracting {tar_filename} from {deb_file}..")

        with open(tar_file_path, "wb") as outfile:
            subprocess.run([ar_tool, "p", os.path.abspath(deb_file), tar_filename], check=True, stdout=outfile, stderr=subprocess.PIPE)

        file_extension = os.path.splitext(tar_file_path)[1].lower()

        if file_extension == ".xz":
            mode = "r:xz"
        elif file_extension == ".gz":
            mode = "r:gz"
        elif file_extension == ".zst":
            # zstd is not supported by standard library yet
            decompressed_tar_path = tar_file_path.replace(".zst", "")
            with open(tar_file_path, "rb") as zst_file, open(decompressed_tar_path, "wb") as decompressed_file:
                dctx = zstandard.ZstdDecompressor()

View on GitHub (pinned to dbf9771522)

Solutions

  1. Inspect the file: `file <deb_file>` (should report 'Debian binary package') and `ls -l` for a plausible size; `ar t <deb_file>` to see members.
  2. Re-download the offending .deb and clear the tmp_dir cache first to rule out a stale partial file.
  3. Confirm the --artool argument names a real ar implementation (`ar --version`); don't point it at llvm-ar unless that's intended for the format.
  4. Free disk space in tmp_dir if it filled up during the parallel download.
Defensive patterns

Strategy: validation

Validate before calling

# Validate a .deb is well-formed (has data.tar) before extract_deb_file
import subprocess, os

def deb_has_data_tar(deb_file, ar_tool='ar'):
    if not os.path.exists(deb_file) or os.path.getsize(deb_file) < 100:
        raise RuntimeError(f"{deb_file} missing or too small - likely a failed download")
    res = subprocess.run([ar_tool, 't', deb_file], capture_output=True, text=True)
    if res.returncode != 0:
        raise RuntimeError(f"{deb_file} is not a valid ar archive: {res.stderr}")
    if not any(line.startswith('data.tar') for line in res.stdout.splitlines()):
        raise RuntimeError(f"{deb_file} has no data.tar member - corrupt/partial; re-download")
    return True

Try / catch

from pathlib import Path
import subprocess

for deb_file in deb_files:
    try:
        extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool)
    except FileNotFoundError as e:
        if "data.tar" in str(e):
            # re-download this one .deb once, then retry; abort if it still fails
            os.remove(deb_file)
            asyncio.run(download_file(session, url_for(deb_file), deb_file, checksum=checksum_for(deb_file)))
            extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool)
        else:
            raise

Prevention

When it happens

Trigger: extract_deb_file on a file at tmp_dir/<basename> where `ar t` output contains no 'data.tar' member. Caused by a partial download (connection dropped mid-file), the mirror serving a 200 OK error page, a cache that stored only part of the file, or an ar tool that silently produced no/partial output.

Common situations: Disk full so the .deb write was truncated; transparent proxy cached a partial body; mirror returned an error page with HTTP 200 so download_file accepted it; tmp_dir cleared mid-run; wrong --artool that doesn't behave like GNU/BSD ar.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/c1bd751120a71d67. Report an issue: GitHub.