headroomlabs-ai/headroom · error · SystemExit

{sdist.name} declares no License-File entries

Error message

{sdist.name} declares no License-File entries

What it means

verify_sdist_license_files() reads the PKG-INFO headers and requires at least one `License-File:` entry. Modern Python packaging (PEP 639) records which license files ship in the sdist; an empty list means the project metadata never declared license files, so downstream consumers get no license text.

Source

Thrown at scripts/build_python_release_smoke.py:143

            raise SystemExit(f"expected one sdist root directory, found {sorted(roots)}")
        root = roots.pop()

        pkg_info_path = f"{root}/PKG-INFO"
        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:

View on GitHub (pinned to 322425c43b)

Solutions

  1. Add license declaration to pyproject.toml, e.g. `license = "MIT"` plus `license-files = ["LICENSE"]` (or the setuptools/maturin equivalent for your builder).
  2. Upgrade maturin to a version that emits PEP 639 License-File metadata.
  3. Rebuild and confirm PKG-INFO now contains `License-File: LICENSE` lines.

Example fix

# pyproject.toml - before
[project]
name = "headroom"
# no license declaration

# after
[project]
name = "headroom"
license = "MIT"
license-files = ["LICENSE"]
Defensive patterns

Strategy: validation

Validate before calling

import tarfile

def declared_license_files(sdist_path: str, root: str) -> list[str]:
    with tarfile.open(sdist_path, "r:gz") as t:
        text = t.extractfile(f"{root}/PKG-INFO").read().decode()
    return [l.split(":", 1)[1].strip() for l in text.splitlines() if l.startswith("License-File:")]
# assert declared_license_files(...) before promoting an sdist

Prevention

When it happens

Trigger: pyproject.toml lacking `license-files` (or `license = {file = ...}` legacy form that some builders do not translate into License-File entries); an older maturin/setuptools that does not emit PEP 639 License-File metadata.

Common situations: Upgrading or downgrading maturin changes whether License-File is emitted; a pyproject cleanup that dropped the license-files key; adding a LICENSE file without wiring it into metadata.

Related errors


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