headroomlabs-ai/headroom · error · SystemExit

{sdist.name} declares License-File entries missing from tarb

Error message

{sdist.name} declares License-File entries missing from tarball: {missing}

What it means

verify_sdist_license_files() cross-checks every `License-File:` entry declared in PKG-INFO against the actual tarball members under the sdist root. An entry that is declared but not present in the archive fails the smoke test, because installing the package would reference license files that do not exist.

Source

Thrown at scripts/build_python_release_smoke.py:147

        member = archive.getmember(pkg_info_path)
        fh = archive.extractfile(member)
        if fh is None:
            raise SystemExit(f"could not read {pkg_info_path} from {sdist.name}")
        pkg_info = fh.read().decode("utf-8")

    declared = []
    for line in pkg_info.splitlines():
        if not line.strip():
            break
        if line.startswith("License-File:"):
            declared.append(line.split(":", 1)[1].strip())

    if not declared:
        raise SystemExit(f"{sdist.name} declares no License-File entries")

    missing = [name for name in declared if f"{root}/{name}" not in names]
    if missing:
        raise SystemExit(
            f"{sdist.name} declares License-File entries missing from tarball: {missing}"
        )

    print(f"sdist License-File metadata OK: {declared}")


def venv_python(venv_dir: Path) -> Path:
    if os.name == "nt":
        return venv_dir / "Scripts" / "python.exe"
    return venv_dir / "bin" / "python"


def smoke_install_wheel(wheel: Path, python_exe: str, expected_version: str) -> None:
    with tempfile.TemporaryDirectory(prefix="headroom-python-smoke-") as tmp:
        venv_dir = Path(tmp) / "venv"
        run([python_exe, "-m", "venv", venv_dir])
        smoke_python = venv_python(venv_dir)

View on GitHub (pinned to 322425c43b)

Solutions

  1. Compare declared entries with archive contents: `tar -tzf file.tar.gz | grep -i license`.
  2. Restore the declared file at the declared path and rebuild, or update the `license-files` list to the new filename.
  3. Check that no exclude rule in pyproject/Cargo config filters out the license file from the sdist.
Defensive patterns

Strategy: validation

Validate before calling

import tarfile

def license_entries_present(sdist_path: str, root: str) -> list[str]:
    with tarfile.open(sdist_path, "r:gz") as t:
        names = set(t.getnames())
        declared = [
            l.split(":", 1)[1].strip()
            for l in t.extractfile(f"{root}/PKG-INFO").read().decode().splitlines()
            if l.startswith("License-File:")
        ]
    return [d for d in declared if f"{root}/{d}" not in names]

Prevention

When it happens

Trigger: PKG-INFO declares `License-File: LICENSE` but the file was excluded from the sdist (missing on disk, excluded by include/exclude rules, or gitignored when building from a dirty tree).

Common situations: Renaming LICENSE to LICENSE.md without updating metadata; maturin sdist exclusion globs matching the license path; building from an exported tree that omitted the license file.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/cff1e0f3a056c147. Report an issue: GitHub.