{"record":{"id":"8f95b372a4ade7a8","repo":"headroomlabs-ai/headroom","slug":"expected-one-sdist-root-directory-found-sorted-r","errorCode":null,"errorMessage":"expected one sdist root directory, found {sorted(roots)}","messagePattern":"expected one sdist root directory, found (.+?)","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/build_python_release_smoke.py","lineNumber":125,"sourceCode":"            raise SystemExit(\n                f\"{wheel.name} should contain exactly one dist-info/METADATA, \"\n                f\"found {len(metadata_members)}\"\n            )\n        metadata = archive.read(metadata_members[0]).decode(\"utf-8\")\n\n    expected_line = f\"Version: {expected_version}\"\n    if expected_line not in metadata.splitlines():\n        raise SystemExit(f\"{wheel.name} metadata missing {expected_line!r}\")\n\n    print(f\"wheel metadata OK: {wheel.name} contains {native_members[0]}\")\n\n\ndef verify_sdist_license_files(sdist: Path) -> None:\n    with tarfile.open(sdist, \"r:gz\") as archive:\n        names = set(archive.getnames())\n        roots = {name.split(\"/\", 1)[0] for name in names if \"/\" in name}\n        if len(roots) != 1:\n            raise SystemExit(f\"expected one sdist root directory, found {sorted(roots)}\")\n        root = roots.pop()\n\n        pkg_info_path = f\"{root}/PKG-INFO\"\n        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\")","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/scripts/build_python_release_smoke.py#L107-L143","documentation":"verify_sdist_license_files() opens the sdist tarball and requires every member to sit under exactly one top-level root directory (the standard `<name>-<version>/` layout sdists use). Multiple roots mean stray top-level files leaked into the archive; zero roots means an effectively empty archive.","triggerScenarios":"maturin including extra top-level files in the sdist (stray files at repo root picked up by include patterns); an sdist built with a non-standard packer; an empty or corrupted tarball.","commonSituations":"Adding generated files at the repo root that maturin's sdist inclusion rules pick up; changing pyproject `[tool.maturin]` include/exclude globs; MANIFEST-style configuration drift.","solutions":["Inspect the archive roots: `tar -tzf file.tar.gz | cut -d/ -f1 | sort -u`.","Move or exclude the stray top-level files (maturin sdist includes/excludes in pyproject.toml) so everything nests under the single `name-version/` root.","Rebuild the sdist in a clean checkout to rule out untracked local files."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import tarfile\n\ndef sdist_roots(sdist_path: str) -> set[str]:\n    with tarfile.open(sdist_path, \"r:gz\") as t:\n        return {n.split(\"/\", 1)[0] for n in t.getnames() if \"/\" in n}\n# assert len(sdist_roots(p)) == 1 before deeper verification","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep generated artifacts out of the repo root or exclude them from sdist inclusion rules.","Review [tool.maturin] include/exclude globs whenever top-level files are added.","Build sdists from a clean export (git archive) when in doubt."],"tags":["python","sdist","packaging","maturin"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}