Bug Description
We are investigating build failures in our software stack we're currently building up.
After installing Rust v1.94.1 and maturin v1.13.1, we tried to build a Python package (tibs) with our standard install procedure:
$ python -m pip install --prefix=[...]/software/tibs/0.6.0-GCCcore-15.2.0 --no-deps --ignore-installed --no-index --no-build-isolation .
In earlier maturin versions, this worked perfectly fine. However, with version v1.13.0 and later, we're getting the following build failure from pip:
Click to open
ERROR: Exception:
Traceback (most recent call last):
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/cli/base_command.py", line 107, in _run_wrapper
status = _inner_run()
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/cli/base_command.py", line 98, in _inner_run
return self.run(options, args)
~~~~~~~~^^^^^^^^^^^^^^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/cli/req_command.py", line 85, in wrapper
return func(self, options, args)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/commands/install.py", line 389, in run
requirement_set = resolver.resolve(
reqs, check_supported_wheels=not options.target_dir
)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 79, in resolve
collected = self.factory.collect_root_requirements(root_reqs)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 538, in collect_root_requirements
reqs = list(
self._make_requirements_from_install_req(
...<2 lines>...
)
)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 494, in _make_requirements_from_install_req
cand = self._make_base_candidate_from_link(
ireq.link,
...<2 lines>...
version=None,
)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 226, in _make_base_candidate_from_link
self._link_candidate_cache[link] = LinkCandidate(
~~~~~~~~~~~~~^
link,
^^^^^
...<3 lines>...
version=version,
^^^^^^^^^^^^^^^^
)
^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 318, in __init__
super().__init__(
~~~~~~~~~~~~~~~~^
link=link,
^^^^^^^^^^
...<4 lines>...
version=version,
^^^^^^^^^^^^^^^^
)
^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 161, in __init__
self.dist = self._prepare()
~~~~~~~~~~~~~^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 238, in _prepare
dist = self._prepare_distribution()
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/resolution/resolvelib/candidates.py", line 329, in _prepare_distribution
return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/operations/prepare.py", line 543, in prepare_linked_requirement
return self._prepare_linked_requirement(req, parallel_builds)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/operations/prepare.py", line 658, in _prepare_linked_requirement
dist = _get_prepared_distribution(
req,
...<3 lines>...
self.check_build_deps,
)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/operations/prepare.py", line 77, in _get_prepared_distribution
abstract_dist.prepare_distribution_metadata(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
build_env_installer, build_isolation, check_build_deps
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/distributions/sdist.py", line 71, in prepare_distribution_metadata
self.req.prepare_metadata()
~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/req/req_install.py", line 538, in prepare_metadata
self._set_requirement()
~~~~~~~~~~~~~~~~~~~~~^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_internal/req/req_install.py", line 373, in _set_requirement
if isinstance(parse_version(self.metadata["Version"]), Version):
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_vendor/packaging/version.py", line 56, in parse
return Version(version)
File "/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/lib/python3.14/site-packages/pip/_vendor/packaging/version.py", line 200, in __init__
match = self._regex.search(version)
TypeError: expected string or bytes-like object, got 'NoneType'
After digging a bit deeper, I suspect that the following things happen:
pip calls into generate_metadata -> prepare_metadata -> prepare_metadata_for_build_wheel. This leads to prepare_metadata_for_build_wheel in maturin.
maturin calls maturin pep517 write-dist-info --metadata-directory [...] --interpreter [...]
maturin returns the last line of the output, not containing the expected output
Checking self.metadata_directory in pip via some print debugging after maturin has finished (i.e. adding a print here, I saw:
/tmp/eb-2gkjwrv2/pip-modern-metadata-8_54kgcy/2026-04-16T15:07:48.084403Z INFO pep517: maturin::commands::pep517: close time.busy=367ms time.idle=11.3µs
Here, we can see some INFO output instead of the directory name.
Running maturin pep517 write-dist-info --metadata-directory [...] --interpreter [...] manually verifies that this is indeed the last line:
eb-shell> maturin pep517 write-dist-info --metadata-directory /tmp/eb-37jjd3ve/pip-modern-metadata-9rw9krgm --interpreter /p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python
2026-04-17T07:37:16.252630Z INFO pep517:into_build_context: maturin::build_options: close time.busy=1.44µs time.idle=810ns
2026-04-17T07:37:16.252805Z DEBUG pep517:build: maturin::project_layout: Found pyproject.toml in working directory at "/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0/pyproject.toml"
2026-04-17T07:37:16.253378Z DEBUG pep517:build: maturin::project_layout: Using cargo manifest path from working directory: "/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0/Cargo.toml"
2026-04-17T07:37:16.253585Z DEBUG pep517:build:resolve_cargo_metadata: maturin::project_layout: Resolving cargo metadata from "/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0/Cargo.toml"
2026-04-17T07:37:16.318621Z INFO pep517:build:resolve_cargo_metadata: maturin::project_layout: close time.busy=65.0ms time.idle=3.50µs
📦 Including license file `LICENSE`
2026-04-17T07:37:16.319311Z DEBUG pep517:build: maturin::project_layout: Project layout resolved project_root=/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0 python_dir=/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0 rust_module=/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0/tibs python_module=Some("/dev/shm/reuter1/easybuild/build/tibs/0.6.0/GCCcore-15.2.0/tibs-0.6.0/tibs") extension_name=tibs module_name=tibs
🔗 Found pyo3 bindings with abi3 support
2026-04-17T07:37:16.319501Z DEBUG pep517:build: maturin::build_context::builder: Resolved bridge model: PyO3(PyO3 { crate_name: pyo3, version: Version { major: 0, minor: 28, patch: 2 }, stable_abi: Some(StableAbi { kind: Abi3, version: Version(3, 8) }), metadata: Some(PyO3Metadata { cpython: PyO3VersionMetadata { min_minor: 7, max_minor: 15 }, pypy: PyO3VersionMetadata { min_minor: 11, max_minor: 11 } }) })
2026-04-17T07:37:16.479623Z DEBUG pep517:build:check_executable: maturin::python_interpreter::discovery: Found CPython interpreter at /p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python executable=/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python
2026-04-17T07:37:16.479676Z INFO pep517:build:check_executable: maturin::python_interpreter::discovery: close time.busy=51.0ms time.idle=2.62µs executable=/p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python
🐍 Found CPython 3.14 at /p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python
📡 Using build options features from pyproject.toml
2026-04-17T07:37:16.479796Z INFO pep517:build: maturin::build_context::builder: close time.busy=227ms time.idle=4.22µs
2026-04-17T07:37:16.482808Z DEBUG pep517: maturin::module_writer::virtual_writer: Tracked entry "tibs-0.6.0.dist-info/METADATA"
2026-04-17T07:37:16.482840Z DEBUG pep517: maturin::module_writer::virtual_writer: Tracked entry "tibs-0.6.0.dist-info/WHEEL"
2026-04-17T07:37:16.482851Z DEBUG pep517: maturin::module_writer::virtual_writer: Tracked entry "tibs-0.6.0.dist-info/licenses/LICENSE"
tibs-0.6.0.dist-info
2026-04-17T07:37:16.483749Z INFO pep517: maturin::commands::pep517: close time.busy=231ms time.idle=13.0µs
Some more debugging and searching later, it looks like this boils down to RUST_LOG=debug being set in our environment. Changing this to e.g. RUST_LOG=warn is sufficient enough to fix the issues we've seen.
eb-shell> RUST_LOG=warn maturin pep517 write-dist-info --metadata-directory /tmp/eb-37jjd3ve/pip-modern-metadata-9rw9krgm --interpreter /p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python
📦 Including license file `LICENSE`
🔗 Found pyo3 bindings with abi3 support
🐍 Found CPython 3.14 at /p/project1/cswmanage/reuter1/EasyBuild/apps/software/Python/3.14.2-GCCcore-15.2.0/bin/python
📡 Using build options features from pyproject.toml
tibs-0.6.0.dist-info
maturin should probably handle the case where an environment might set RUST_LOG=[...], especially as the output is being parsed in prepare_metadata_for_build_wheel.
Options might include to override / unset RUST_LOG for this particular call only, or to add a more robust handling for the returned directory name.
Your maturin version (maturin --version)
1.13.0, 1.13.1
Your Python version (python -V)
3.14.2
Your pip version (pip -V)
25.3
What bindings you're using
None
Does cargo build work?
If on windows, have you checked that you aren't accidentally using unix path (those with the forward slash /)?
The issues were encountered on different Linux systems (Arch Linux, Rocky Linux 9, RHEL, ...)
Steps to Reproduce
- Install
maturin in a virtual environment:
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install maturin==1.13.1
- Try to install a package with
RUST_LOG=debug set:
$ RUST_LOG=debug pip install --no-deps --ignore-installed --no-index --no-build-isolation https://github.com/scott-griffiths/tibs/archive/refs/tags/v0.6.0.tar.gz
This should yield the same error reported above:
File "/home/jreuter/venv/lib/python3.14/site-packages/pip/_internal/distributions/sdist.py", line 71, in prepare_distribution_metadata
self.req.prepare_metadata()
~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/home/jreuter/venv/lib/python3.14/site-packages/pip/_internal/req/req_install.py", line 538, in prepare_metadata
self._set_requirement()
~~~~~~~~~~~~~~~~~~~~~^^
File "/home/jreuter/venv/lib/python3.14/site-packages/pip/_internal/req/req_install.py", line 373, in _set_requirement
if isinstance(parse_version(self.metadata["Version"]), Version):
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jreuter/venv/lib/python3.14/site-packages/pip/_vendor/packaging/version.py", line 103, in parse
return Version(version)
File "/home/jreuter/venv/lib/python3.14/site-packages/pip/_vendor/packaging/version.py", line 359, in __init__
match = self._regex.fullmatch(version)
TypeError: expected string or bytes-like object, got 'NoneType'
Bug Description
We are investigating build failures in our software stack we're currently building up.
After installing Rust v1.94.1 and maturin v1.13.1, we tried to build a Python package (tibs) with our standard install procedure:
In earlier
maturinversions, this worked perfectly fine. However, with version v1.13.0 and later, we're getting the following build failure frompip:Click to open
After digging a bit deeper, I suspect that the following things happen:
pipcalls intogenerate_metadata -> prepare_metadata -> prepare_metadata_for_build_wheel. This leads toprepare_metadata_for_build_wheelinmaturin.maturincallsmaturin pep517 write-dist-info --metadata-directory [...] --interpreter [...]maturinreturns the last line of the output, not containing the expected outputChecking
self.metadata_directoryinpipvia someprintdebugging aftermaturinhas finished (i.e. adding a print here, I saw:Here, we can see some
INFOoutput instead of the directory name.Running
maturin pep517 write-dist-info --metadata-directory [...] --interpreter [...]manually verifies that this is indeed the last line:Some more debugging and searching later, it looks like this boils down to
RUST_LOG=debugbeing set in our environment. Changing this to e.g.RUST_LOG=warnis sufficient enough to fix the issues we've seen.maturinshould probably handle the case where an environment might setRUST_LOG=[...], especially as the output is being parsed inprepare_metadata_for_build_wheel.Options might include to override / unset
RUST_LOGfor this particular call only, or to add a more robust handling for the returned directory name.Your maturin version (
maturin --version)1.13.0, 1.13.1
Your Python version (
python -V)3.14.2
Your pip version (
pip -V)25.3
What bindings you're using
None
Does
cargo buildwork?If on windows, have you checked that you aren't accidentally using unix path (those with the forward slash
/)?The issues were encountered on different Linux systems (Arch Linux, Rocky Linux 9, RHEL, ...)
Steps to Reproduce
maturinin a virtual environment:RUST_LOG=debugset:$ RUST_LOG=debug pip install --no-deps --ignore-installed --no-index --no-build-isolation https://github.com/scott-griffiths/tibs/archive/refs/tags/v0.6.0.tar.gzThis should yield the same error reported above: