pypa/pip · error · InvalidWheel

Wheel '{name}' located at {location} is invalid.

Error message

Wheel '{name}' located at {location} is invalid.

What it means

InvalidWheel raised by Distribution.from_wheel() (pkg_resources backend) when wheel.as_zipfile() raises zipfile.BadZipFile, or when an UnsupportedWheel propagates and is re-wrapped. The .whl file is not a valid ZIP (or its internal structure is unparseable), so pkg_resources cannot construct the distribution.

Source

Thrown at src/pip/_internal/metadata/pkg_resources.py:149

        dist = pkg_resources.DistInfoDistribution(
            location=filename,
            metadata=InMemoryMetadata(metadata_dict, filename),
            project_name=project_name,
        )
        return cls(dist)

    @classmethod
    def from_wheel(cls, wheel: Wheel, name: str) -> BaseDistribution:
        try:
            with wheel.as_zipfile() as zf:
                info_dir, _ = parse_wheel(zf, name)
                metadata_dict = {
                    path.split("/", 1)[-1]: read_wheel_metadata_file(zf, path)
                    for path in zf.namelist()
                    if path.startswith(f"{info_dir}/")
                }
        except zipfile.BadZipFile as e:
            raise InvalidWheel(wheel.location, name) from e
        except UnsupportedWheel as e:
            raise UnsupportedWheel(f"{name} has an invalid wheel, {e}")
        dist = pkg_resources.DistInfoDistribution(
            location=wheel.location,
            metadata=InMemoryMetadata(metadata_dict, wheel.location),
            project_name=name,
        )
        return cls(dist)

    @property
    def location(self) -> str | None:
        return self._dist.location

    @property
    def installed_location(self) -> str | None:
        egg_link = egg_link_path_from_location(self.raw_name)
        if egg_link:
            location = egg_link

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Purge the cache (pip cache purge) and reinstall with --no-cache-dir.
  2. Verify the wheel hash against PyPI to detect corruption.
  3. Re-download directly from PyPI, bypassing mirrors/proxies.
  4. If the inner cause is an unsupported wheel, address that specific metadata issue once the file is valid.

Example fix

# before
pip install ./somepkg-1.0-py3-none-any.whl   # corrupt file

# after
pip cache purge
pip install --no-cache-dir somepkg
Defensive patterns

Strategy: validation

Validate before calling

import zipfile
try:
    with zipfile.ZipFile(path) as zf:
        assert zf.testzip() is None
        # also ensure a .dist-info exists
        assert any(n.endswith('.dist-info/METADATA') for n in zf.namelist())
    print('valid wheel')
except (zipfile.BadZipFile, AssertionError):
    print('invalid wheel')

Type guard

def is_valid_wheel(path: str) -> bool:
    import zipfile
    try:
        with zipfile.ZipFile(path) as zf:
            return zf.testzip() is None and any(
                n.endswith('.dist-info/METADATA') for n in zf.namelist())
    except zipfile.BadZipFile:
        return False

Try / catch

from pip._internal.exceptions import InvalidWheel, UnsupportedWheel
try:
    dist = Distribution.from_wheel(wheel, name)
except InvalidWheel:
    # purge cache, re-download
except UnsupportedWheel as e:
    # inner metadata issue; address specifics
    ...

Prevention

When it happens

Trigger: Reached while loading a wheel via the pkg_resources metadata backend: opening the file as a zip fails because it is truncated, corrupt, or not actually a zip. Also re-raises an inner UnsupportedWheel as 'X has an invalid wheel, ...'.

Common situations: Corrupted download, partial file in pip cache, a mirror/proxy serving an error page with a .whl extension, or a wheel whose dist-info structure is invalid (re-wrapped UnsupportedWheel).

Related errors


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