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

  1. Clear pip's cache: 'pip cache purge', then reinstall
  2. Verify the wheel integrity: 'unzip -t <file>.whl'
  3. Re-download the wheel from the official PyPI index
  4. Rebuild the wheel with 'python -m build --wheel'
  5. 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

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


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)