Skip to content

RUST_LOG influences returned directory in prepare_metadata_for_build_wheel #3141

@Thyre

Description

@Thyre

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:

  1. pip calls into generate_metadata -> prepare_metadata -> prepare_metadata_for_build_wheel. This leads to prepare_metadata_for_build_wheel in maturin.
  2. maturin calls maturin pep517 write-dist-info --metadata-directory [...] --interpreter [...]
  3. 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?

  • Yes, it works

If on windows, have you checked that you aren't accidentally using unix path (those with the forward slash /)?

  • Yes

The issues were encountered on different Linux systems (Arch Linux, Rocky Linux 9, RHEL, ...)

Steps to Reproduce

  1. Install maturin in a virtual environment:
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install maturin==1.13.1
  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'

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions