pypa/pip · error · UnsupportedWheel
could not read file
Error message
could not read {path!r} file: {e!r} What it means
Raised by read_wheel_metadata_file() when reading a file from the wheel zip raises BadZipFile (general corruption), KeyError (entry missing), or RuntimeError (password-protected zip). It indicates the wheel's internal metadata file could not be read from the archive.
Solutions
- Clear pip's cache: 'pip cache purge', then reinstall
- Verify the wheel integrity: 'unzip -t <file>.whl'
- Re-download the wheel from the official PyPI index
- Rebuild the wheel with 'python -m build --wheel'
- Check for a password-protected zip and rebuild without a password
Example fix
// before pip install ./possibly-corrupt-1.0-py3-none-any.whl // after pip cache purge unzip -t possibly-corrupt-1.0-py3-none-any.whl # if the test fails, re-download or rebuild pip install --force-reinstall possibly-corrupt==1.0
Defensive patterns
Strategy: validation
Validate before calling
import zipfile
def wheel_files_are_readable(path: str) -> bool:
try:
with zipfile.ZipFile(path) as zf:
for name in zf.namelist():
if name.endswith('.dist-info/WHEEL'):
zf.read(name)
return True
return False
except (zipfile.BadZipFile, KeyError, RuntimeError):
return False Type guard
import zipfile
def is_intact_wheel_zip(path: str) -> bool:
try:
with zipfile.ZipFile(path) as zf:
zf.testzip() # returns None if OK
return True
except (zipfile.BadZipFile, RuntimeError):
return False Try / catch
from pip._internal.exceptions import UnsupportedWheel
try:
read_wheel_metadata_file(wheel_zip, path)
except UnsupportedWheel as e:
if 'could not read' in str(e):
# re-download or rebuild the wheel
raise PackagingError(f'wheel metadata unreadable, re-download: {e}')
raise Prevention
- Verify zip integrity with 'unzip -t <file>.whl' before installing
- Clear pip cache ('pip cache purge') to remove corrupt cached downloads
- Do not password-protect wheel zips
- Re-download from the official index
When it happens
Trigger: Calling read_wheel_metadata_file(source, path) where source.read(path) fails. Reached when pip reads the WHEEL or METADATA file from the .dist-info directory during wheel installation via parse_wheel().
Common situations: A truncated or corrupt wheel download (BadZipFile). A wheel built without the expected metadata file (KeyError). A password-protected zip mislabeled as a wheel (RuntimeError). Disk corruption or an interrupted download cached by pip.
Related errors
- .dist-info directory
- .dist-info directory not found
- error decoding
- invalid Wheel-Version
- multiple .dist-info directories found
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/02ca0dd7105eabd7.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/utils/wheel.py:73
info_dir = info_dirs[0]
info_dir_name = canonicalize_name(info_dir)
canonical_name = canonicalize_name(name)
if not info_dir_name.startswith(canonical_name):
raise UnsupportedWheel(
f".dist-info directory {info_dir!r} does not start with {canonical_name!r}"
)
return info_dir
def read_wheel_metadata_file(source: ZipFile, path: str) -> bytes:
try:
return source.read(path)
# BadZipFile for general corruption, KeyError for missing entry,
# and RuntimeError for password-protected files
except (BadZipFile, KeyError, RuntimeError) as e:
raise UnsupportedWheel(f"could not read {path!r} file: {e!r}")
def wheel_metadata(source: ZipFile, dist_info_dir: str) -> Message:
"""Return the WHEEL metadata of an extracted wheel, if possible.
Otherwise, raise UnsupportedWheel.
"""
path = f"{dist_info_dir}/WHEEL"
# Zip file path separators must be /
wheel_contents = read_wheel_metadata_file(source, path)
try:
wheel_text = wheel_contents.decode()
except UnicodeDecodeError as e:
raise UnsupportedWheel(f"error decoding {path!r}: {e!r}")
# FeedParser (used by Parser) does not raise any exceptions. The returned
# message may have .defects populated, but for backwards-compatibility we
# currently ignore them.View on GitHub (pinned to f399c37189)