pypa/pip · error · UnsupportedWheel

Metadata 1.2 mandates PEP 440 version, but {dist_verstr!r} i

Error message

Metadata 1.2 mandates PEP 440 version, but {dist_verstr!r} is not

What it means

Raised by `_verify_one` when the wheel declares `Metadata-Version >= 1.2` (which mandates a PEP 440 compliant version string) but the distribution's version object is not a `pip._vendor.packaging.version.Version` (i.e. it is an `EpochVersion`/Legacy/invalid form). PEP 345/426/PEP 440 require versions in metadata >= 1.2 to be strict PEP 440; otherwise the wheel is considered unsupported.

Source

Thrown at src/pip/_internal/wheel_builder.py:116

            f"got {w.name!r}",
        )
    dist = get_wheel_distribution(FilesystemWheel(wheel_path), canonical_name)
    dist_verstr = str(dist.version)
    if canonicalize_version(dist_verstr) != canonicalize_version(w.version):
        raise InvalidWheelFilename(
            f"Wheel has unexpected file name: expected {dist_verstr!r}, "
            f"got {w.version!r}",
        )
    metadata_version_value = dist.metadata_version
    if metadata_version_value is None:
        raise UnsupportedWheel("Missing Metadata-Version")
    try:
        metadata_version = Version(metadata_version_value)
    except InvalidVersion:
        msg = f"Invalid Metadata-Version: {metadata_version_value}"
        raise UnsupportedWheel(msg)
    if metadata_version >= Version("1.2") and not isinstance(dist.version, Version):
        raise UnsupportedWheel(
            f"Metadata 1.2 mandates PEP 440 version, but {dist_verstr!r} is not"
        )


def _build_one(
    req: InstallRequirement,
    output_dir: str,
    verify: bool,
    editable: bool,
) -> str | None:
    """Build one wheel.

    :return: The filename of the built wheel, or None if the build failed.
    """
    artifact = "editable" if editable else "wheel"
    try:
        ensure_dir(output_dir)
    except OSError as e:

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Rewrite the version string to be PEP 440 compliant: `1.0a1`, `1.0rc1`, `1.0.post1`, `1.0.dev1` (use dots not dashes, no leading `v`).
  2. If you must keep a non-PEP 440 version, you cannot declare `Metadata-Version >= 1.2`; but the right fix is to make the version compliant.
  3. Use `from packaging.version import Version; Version(your_version)` locally to validate before building.

Example fix

# before
[project]
name = "mypkg"
version = "1.0-rc1"        # not PEP 440
# METADATA: Metadata-Version: 2.1

# after
[project]
name = "mypkg"
version = "1.0rc1"        # PEP 440 compliant
Defensive patterns

Strategy: validation

Validate before calling

from packaging.version import Version, InvalidVersion

def assert_pep440_version(version: str) -> None:
    try:
        Version(version)
    except InvalidVersion:
        raise ValueError(f"{version!r} is not a PEP 440 version")

# before building:
assert_pep440_version(project_version)

Type guard

from packaging.version import Version, InvalidVersion

def is_pep440(v: str) -> bool:
    try:
        Version(v)
        return True
    except InvalidVersion:
        return False

Try / catch

from pip._internal.exceptions import UnsupportedWheel
try:
    _verify_one(req, wheel_path)
except UnsupportedWheel as e:
    if "mandates PEP 440" in str(e):
        # fix version string in pyproject/setup
        ...

Prevention

When it happens

Trigger: `metadata_version >= Version('1.2')` and `not isinstance(dist.version, Version)` in `_verify_one`. Happens when a project declares `Metadata-Version: 1.2` (or higher) but its version string is non-PEP-440 (e.g. `1.0-alpha`, `1.0.dev1x`, legacy `1.0-1`).

Common situations: Projects with hand-written version strings not following PEP 440 (e.g. `1.0rc`, `1.0.0.beta`, dashes instead of PEP 440 separators); upgrading Metadata-Version without fixing the version; legacy packages re-packaged with modern metadata.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/5a5b4a0ab47fd10b.json. Report an issue: GitHub.