{"record":{"id":"01b42724bef0d8d3","repo":"headroomlabs-ai/headroom","slug":"wheel-name-does-not-contain-headroom-core-nativ","errorCode":null,"errorMessage":"{wheel.name} does not contain headroom/_core native extension","messagePattern":"(.+?) does not contain headroom/_core native extension","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/build_python_release_smoke.py","lineNumber":103,"sourceCode":"\n\ndef find_one_artifact(out_dir: Path, pattern: str) -> Path:\n    matches = sorted(out_dir.glob(pattern))\n    if len(matches) != 1:\n        raise SystemExit(f\"expected exactly one {pattern} in {out_dir}, found {len(matches)}\")\n    return matches[0]\n\n\ndef verify_wheel(wheel: Path, expected_version: str) -> None:\n    with zipfile.ZipFile(wheel) as archive:\n        names = set(archive.namelist())\n        native_members = [\n            name\n            for name in names\n            if name.startswith(\"headroom/_core\") and Path(name).suffix.lower() in {\".pyd\", \".so\"}\n        ]\n        if not native_members:\n            raise SystemExit(f\"{wheel.name} does not contain headroom/_core native extension\")\n\n        metadata_members = [name for name in names if name.endswith(\".dist-info/METADATA\")]\n        if len(metadata_members) != 1:\n            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:","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/scripts/build_python_release_smoke.py#L85-L121","documentation":"verify_wheel() opens the built wheel and requires at least one compiled extension module under `headroom/_core` (a `.so` or `.pyd` file). This project is a PyO3/Rust extension shipped as a wheel, so a wheel without a native module means the Python package would silently fall back to nothing at runtime — the smoke test blocks that.","triggerScenarios":"Building the wheel without the Rust extension compiling (maturin succeeded but the extension module was skipped or renamed); the package layout changed so the extension lives somewhere other than `headroom/_core`; building a pure-Python wheel by accident (e.g., `python -m build --wheel` on the Python package instead of `maturin build`).","commonSituations":"Cargo/Rust toolchain missing in CI so the extension is never produced; module path renamed in pyo3 config (`name = \"_core\"` under a different package); abi3 forward compatibility producing a differently-suffixed file; wheel built from the sdist re-packaged by a non-maturin builder.","solutions":["Open the wheel (`unzip -l wheel/*.whl | grep headroom/_core`) and check where the extension actually landed; adjust the verify prefix if the layout legitimately changed.","Confirm the build used `maturin build`, not `pip wheel` or `python -m build`, so the Rust extension is compiled in.","Check the Cargo build log for errors and that the Rust toolchain is installed (`cargo --version`).","Verify the pyo3 module config in pyproject/Cargo.toml still names the module `_core` inside the `headroom` package."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import zipfile\n\ndef wheel_has_native_ext(wheel_path: str, prefix: str = \"headroom/_core\") -> bool:\n    with zipfile.ZipFile(wheel_path) as z:\n        return any(\n            n.startswith(prefix) and n.rsplit(\".\", 1)[-1].lower() in {\"so\", \"pyd\"}\n            for n in z.namelist()\n        )","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always build extension wheels with maturin; never repackage with pip/build.","Verify the Rust toolchain is present in CI before the build step (`cargo --version`).","If the module path changes, update the verifier prefix in the same commit."],"tags":["python","pyo3","maturin","rust","wheel"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}