pypa/pip · error · UnsupportedWheel

Error decoding metadata for {wheel}: {e} in {filename} file

Error message

Error decoding metadata for {wheel}: {e} in {filename} file

What it means

UnsupportedWheel raised by WheelDistribution.read_text() when a metadata file inside the wheel (METADATA / WHEEL / entry_points etc.) cannot be decoded as UTF-8. The wheel is structurally a valid zip but its metadata bytes are not valid UTF-8, so importlib.metadata cannot parse it.

Source

Thrown at src/pip/_internal/metadata/importlib/_dists.py:93

        return cls(files, info_location)

    def iterdir(self, path: InfoPath) -> Iterator[pathlib.PurePosixPath]:
        # Only allow iterating through the metadata directory.
        if pathlib.PurePosixPath(str(path)) in self._files:
            return iter(self._files)
        raise FileNotFoundError(path)

    def read_text(self, filename: str) -> str | None:
        try:
            data = self._files[pathlib.PurePosixPath(filename)]
        except KeyError:
            return None
        try:
            text = data.decode("utf-8")
        except UnicodeDecodeError as e:
            wheel = self.info_location.parent
            error = f"Error decoding metadata for {wheel}: {e} in {filename} file"
            raise UnsupportedWheel(error)
        return text

    def locate_file(self, path: str | PathLike[str]) -> pathlib.Path:
        # This method doesn't make sense for our in-memory wheel, but the API
        # requires us to define it.
        raise NotImplementedError


class Distribution(BaseDistribution):
    def __init__(
        self,
        dist: importlib.metadata.Distribution,
        info_location: BasePath | None,
        installed_location: BasePath | None,
    ) -> None:
        self._dist = dist
        self._info_location = info_location
        self._installed_location = installed_location

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Re-download the wheel (verify its hash) in case of transfer corruption.
  2. Rebuild the wheel with a current build backend (build/hatch/setuptools>=64) that emits UTF-8 metadata.
  3. Report to the package maintainer if a published wheel ships non-UTF-8 metadata.
  4. Force a source install (--no-binary) to bypass the broken wheel.

Example fix

# before - install a wheel with latin-1 METADATA
pip install somepkg-1.0-py3-none-any.whl

# after
pip install --no-binary somepkg somepkg   # build from sdist
# or rebuild the wheel correctly
python -m build --wheel
Defensive patterns

Strategy: validation

Validate before calling

import zipfile
with zipfile.ZipFile(wheel_path) as zf:
    for n in zf.namelist():
        if n.endswith(('METADATA','RECORD','WHEEL','entry_points.txt')):
            try:
                zf.read(n).decode('utf-8')
            except UnicodeDecodeError:
                print(f'{n} in {wheel_path} is not UTF-8')

Type guard

def wheel_metadata_utf8(path: str) -> bool:
    import zipfile
    try:
        with zipfile.ZipFile(path) as zf:
            for n in zf.namelist():
                if n.endswith(('METADATA','WHEEL')):
                    zf.read(n).decode('utf-8')
        return True
    except (UnicodeDecodeError, zipfile.BadZipFile):
        return False

Try / catch

from pip._internal.exceptions import UnsupportedWheel
try:
    dist = Distribution.from_wheel(wheel, name)
except UnsupportedWheel as e:
    if 'decoding metadata' in str(e):
        # rebuild or re-download the wheel
        ...

Prevention

When it happens

Trigger: Reached while reading an in-memory wheel's metadata file: data.decode('utf-8') raises UnicodeDecodeError. The offending filename is included in the message along with the wheel location.

Common situations: A wheel built with a non-UTF-8 locale or an old tool that wrote metadata in latin-1/cp1252; a metadata file accidentally containing binary garbage; a corrupt wheel download producing non-UTF-8 bytes.

Related errors


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