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
- Add license declaration to pyproject.toml, e.g. `license = "MIT"` plus `license-files = ["LICENSE"]` (or the setuptools/maturin equivalent for your builder).
- Upgrade maturin to a version that emits PEP 639 License-File metadata.
- 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
- Declare license and license-files in pyproject.toml when the project gains a LICENSE file.
- Pin a maturin version known to emit PEP 639 metadata, and keep it in CI.
- Include the license smoke in every release checklist.
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
- expected one sdist root directory, found {sorted(roots)}
- {sdist.name} declares License-File entries missing from tarb
- expected exactly one {pattern} in {out_dir}, found {len(matc
- {wheel.name} does not contain headroom/_core native extensio
- {wheel.name} should contain exactly one dist-info/METADATA,
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/52cae35c4e60a233.
Report an issue: GitHub.