{"record":{"id":"cff1e0f3a056c147","repo":"headroomlabs-ai/headroom","slug":"sdist-name-declares-license-file-entries-missing","errorCode":null,"errorMessage":"{sdist.name} declares License-File entries missing from tarball: {missing}","messagePattern":"(.+?) declares License-File entries missing from tarball: (.+?)","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/build_python_release_smoke.py","lineNumber":147,"sourceCode":"        member = archive.getmember(pkg_info_path)\n        fh = archive.extractfile(member)\n        if fh is None:\n            raise SystemExit(f\"could not read {pkg_info_path} from {sdist.name}\")\n        pkg_info = fh.read().decode(\"utf-8\")\n\n    declared = []\n    for line in pkg_info.splitlines():\n        if not line.strip():\n            break\n        if line.startswith(\"License-File:\"):\n            declared.append(line.split(\":\", 1)[1].strip())\n\n    if not declared:\n        raise SystemExit(f\"{sdist.name} declares no License-File entries\")\n\n    missing = [name for name in declared if f\"{root}/{name}\" not in names]\n    if missing:\n        raise SystemExit(\n            f\"{sdist.name} declares License-File entries missing from tarball: {missing}\"\n        )\n\n    print(f\"sdist License-File metadata OK: {declared}\")\n\n\ndef venv_python(venv_dir: Path) -> Path:\n    if os.name == \"nt\":\n        return venv_dir / \"Scripts\" / \"python.exe\"\n    return venv_dir / \"bin\" / \"python\"\n\n\ndef smoke_install_wheel(wheel: Path, python_exe: str, expected_version: str) -> None:\n    with tempfile.TemporaryDirectory(prefix=\"headroom-python-smoke-\") as tmp:\n        venv_dir = Path(tmp) / \"venv\"\n        run([python_exe, \"-m\", \"venv\", venv_dir])\n        smoke_python = venv_python(venv_dir)\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/scripts/build_python_release_smoke.py#L129-L165","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Compare declared entries with archive contents: `tar -tzf file.tar.gz | grep -i license`.","Restore the declared file at the declared path and rebuild, or update the `license-files` list to the new filename.","Check that no exclude rule in pyproject/Cargo config filters out the license file from the sdist."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import tarfile\n\ndef license_entries_present(sdist_path: str, root: str) -> list[str]:\n    with tarfile.open(sdist_path, \"r:gz\") as t:\n        names = set(t.getnames())\n        declared = [\n            l.split(\":\", 1)[1].strip()\n            for l in t.extractfile(f\"{root}/PKG-INFO\").read().decode().splitlines()\n            if l.startswith(\"License-File:\")\n        ]\n    return [d for d in declared if f\"{root}/{d}\" not in names]","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Rename the license file and the license-files metadata in the same change.","Check sdist exclude rules after touching packaging config.","Build release sdists from a clean checkout so tracked files cannot go missing."],"tags":["python","licensing","sdist","packaging"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}