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() (importlib backend) when wheel.as_zipfile() fails with zipfile.BadZipFile - the file is named *.whl but is not a valid ZIP archive, so it cannot be opened/read at all. Distinct from UnsupportedWheel (bad contents) in that the file itself is not even a zip.
Source
Thrown at src/pip/_internal/metadata/importlib/_dists.py:142
project_name: str,
) -> BaseDistribution:
# Generate temp dir to contain the metadata file, and write the file contents.
temp_dir = pathlib.Path(
TempDirectory(kind="metadata", globally_managed=True).path
)
metadata_path = temp_dir / "METADATA"
metadata_path.write_bytes(metadata_contents)
# Construct dist pointing to the newly created directory.
dist = importlib.metadata.Distribution.at(metadata_path.parent)
return cls(dist, metadata_path.parent, None)
@classmethod
def from_wheel(cls, wheel: Wheel, name: str) -> BaseDistribution:
try:
with wheel.as_zipfile() as zf:
dist = WheelDistribution.from_zipfile(zf, name, wheel.location)
except zipfile.BadZipFile as e:
raise InvalidWheel(wheel.location, name) from e
return cls(dist, dist.info_location, pathlib.PurePosixPath(wheel.location))
@property
def location(self) -> str | None:
if self._info_location is None:
return None
return str(self._info_location.parent)
@property
def info_location(self) -> str | None:
if self._info_location is None:
return None
return str(self._info_location)
@property
def installed_location(self) -> str | None:
if self._installed_location is None:
return NoneView on GitHub (pinned to d7d0d0a394)
Solutions
- Clear the pip cache (pip cache purge) and re-download the wheel.
- Verify the wheel hash if one is pinned; a mismatch confirms corruption.
- Re-download from PyPI directly to rule out a proxy/mirror serving bad files.
- If building locally, rebuild and re-export the wheel cleanly.
Example fix
# before - corrupted cached wheel pip install somepkg # 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:
bad = zf.testzip() # None if OK
print('valid zip' if bad is None else f'corrupt entry: {bad}')
except zipfile.BadZipFile:
print('not a valid zip / wheel') Type guard
def is_valid_wheel_zip(path: str) -> bool:
import zipfile
try:
with zipfile.ZipFile(path) as zf:
return zf.testzip() is None
except zipfile.BadZipFile:
return False Try / catch
from pip._internal.exceptions import InvalidWheel
try:
dist = Distribution.from_wheel(wheel, name)
except InvalidWheel:
# purge cache and re-download
... Prevention
- Verify wheel hashes against PyPI before installing.
- Clear pip cache when corruption is suspected (pip cache purge).
- Re-download with --no-cache-dir to bypass bad cache entries.
- Fetch directly from PyPI to avoid mirror/proxy corruption.
When it happens
Trigger: Reached while preparing a wheel-based distribution: opening the .whl with zipfile raises BadZipFile because the file is truncated, corrupted, or not actually a zip (e.g. an HTML error page saved as .whl, a partial download).
Common situations: A truncated download (network drop) leaving an incomplete .whl; a cache (pip cache) containing a corrupted file; a custom index returning an error page with a .whl URL; disk corruption.
Related errors
- Wheel '{name}' located at {location} is invalid.
- Bad metadata in {dist} (invalid metadata entry 'name')
- could not read {path!r} file: {e!r}
- Too many arguments
- Please provide a pattern
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/e70c7d4079ec78b8.json.
Report an issue: GitHub.