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
- 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.
- Re-download the offending .deb and clear the tmp_dir cache first to rule out a stale partial file.
- 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.
- 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
- After download, check each .deb size and `file <deb>` reports 'Debian binary package'.
- Ensure tmp_dir has free disk space before the parallel download.
- Clear the tmp cache between runs so partial files don't linger.
- Verify the --artool is GNU/BSD ar before the run.
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.