dotnet/yarp · error · FileNotFoundError

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

Error message

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

What it means

This FileNotFoundError is raised in extract_deb_file after running 'ar t <deb_file>' to list the archive's member files. The code scans stdout lines for one starting with 'data.tar' (the member that holds the actual package payload). If no such member is found, the .deb file does not contain a data.tar archive -- meaning it is not a valid Debian package, is corrupted, was truncated during download, or is actually a different file type (e.g. an HTML error page saved with a .deb extension).

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 bd11867bee)

Solutions

  1. Check the file type: run file <deb_file> to confirm it is actually a Debian binary package (should report 'Debian binary package').
  2. Inspect the file size -- if it is suspiciously small (a few KB), it is likely an error page, not a real package.
  3. Manually run: ar t <deb_file> to see what members are listed and confirm the ar tool works.
  4. Verify the download succeeded -- check for a SHA256 mismatch (error 102) that may have been logged but the file still written.
  5. Re-download the specific .deb file and verify its integrity before extraction.
  6. Ensure the correct ar tool is available: which ar (or specify --artool llvm-ar explicitly).
  7. Add a pre-extraction check: verify the file starts with the '!<arch>' magic bytes that identify ar archives.

Example fix

# before -- assumes data.tar always exists in the .deb
if not tar_filename:
    raise FileNotFoundError(f"Could not find 'data.tar.*' in {deb_file}.")

# after -- verify the file is a valid .deb before attempting extraction
with open(deb_file, 'rb') as f:
    magic = f.read(8)
if magic != b'!<arch>':
    raise FileNotFoundError(
        f"{deb_file} is not a valid Debian archive (bad magic: {magic!r}). "
        f"The download may have saved an error page.")
if not tar_filename:
    raise FileNotFoundError(f"Could not find 'data.tar.*' in {deb_file}.")
Defensive patterns

Strategy: validation

Validate before calling

# Pre-check: verify the file is a valid ar archive before extraction.
import os
_DEB_MAGIC = b'!<arch>'
def is_valid_deb(path):
    if not os.path.exists(path) or os.path.getsize(path) < 100:
        return False
    with open(path, 'rb') as f:
        return f.read(8) == _DEB_MAGIC

Type guard

# Check ar archive magic bytes
def is_ar_archive(path):
    try:
        with open(path, 'rb') as f:
            return f.read(8) == b'!<arch>'
    except (OSError, IOError):
        return False

Try / catch

# Wrap extraction and skip corrupt .deb files
try:
    extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool)
except FileNotFoundError as e:
    if 'data.tar' in str(e):
        print(f"WARNING: {deb_file} has no data.tar member. File may be corrupt. Skipping.")
        continue
    raise

Prevention

When it happens

Trigger: extract_deb_file (lines 293-308) runs subprocess.run([ar_tool, 't', deb_file]) and iterates result.stdout lines looking for one starting with 'data.tar'. If none is found, tar_filename stays None and the exception fires. This occurs when: the downloaded .deb is an HTML error page (404/403 page saved as .deb) because the download status wasn't checked properly; the file was truncated; the file is a .udeb or other variant with a different internal structure; the ar_tool ('ar' or 'llvm-ar') failed silently or returned unexpected output format; the file is genuinely corrupt.

Common situations: A 404 or 403 response body was saved as a .deb file because the download path returned non-200 but the error wasn't propagated (related to error 103's retry bug); the .deb was partially downloaded (network interruption, disk full); the file is actually a .rpm, .tar, or HTML page mislabeled; the ar tool path is wrong or ar is not installed, causing 'ar t' to produce empty stdout (though check=True should catch non-zero exit); using llvm-ar which may output member names in a different format; the .deb uses a non-standard archive format.

Related errors


AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13). Data as JSON: /api/errors/4d3e754141e8e688. Report an issue: GitHub.