pypa/pip · error · InvalidWheel

Wheel ' ' located at is invalid.

Error message

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

What it means

Raised as InvalidWheel from Distribution.from_wheel in pkg_resources.py:139-149 when wheel.as_zipfile() raises zipfile.BadZipFile. The pkg_resources-based metadata backend opens the wheel as a zip to extract the dist-info metadata; a structurally corrupt wheel triggers BadZipFile, wrapped as InvalidWheel(location, name).

Solutions

  1. Purge pip's cache (pip cache purge) and re-download the wheel.
  2. Verify the wheel size/hash against the index; re-download if mismatched.
  3. Rebuild the wheel locally if it is your own package.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before opening the wheel, verify it is a complete, valid zip:
import zipfile
if not zipfile.is_zipfile(wheel.location):
    raise SystemExit(f'{wheel.location} corrupt; re-download')

Try / catch

from pip._internal.exceptions import InvalidWheel
try:
    dist = Distribution.from_wheel(wheel, name)
except InvalidWheel:
    # purge cache and re-download
    ...

Prevention

When it happens

Trigger: Distribution.from_wheel(wheel, name) in the pkg_resources backend; the zip is corrupt/truncated so zipfile.BadZipFile is raised and re-raised as InvalidWheel.

Common situations: Corrupted/partial wheel download (network/proxy issue), a file not actually a zip renamed .whl, disk corruption, or a stale partial file in the cache.

Related errors


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

Appendix: 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 f399c37189)