pypa/pip · error · UnsupportedWheel

.dist-info directory not found

Error message

.dist-info directory not found

What it means

UnsupportedWheel raised by wheel_dist_info_dir when no top-level directory ending in `.dist-info` exists in the wheel zip. A valid wheel must contain exactly one `<name>-<version>.dist-info` directory holding its metadata. Absence means the archive is structurally not a wheel.

Source

Thrown at src/pip/_internal/utils/wheel.py:48

    check_compatibility(version, name)

    return info_dir, metadata


def wheel_dist_info_dir(source: ZipFile, name: str) -> str:
    """Returns the name of the contained .dist-info directory.

    Raises AssertionError or UnsupportedWheel if not found, >1 found, or
    it doesn't match the provided name.
    """
    # Zip file path separators must be /
    subdirs = {p.split("/", 1)[0] for p in source.namelist()}

    info_dirs = [s for s in subdirs if s.endswith(".dist-info")]

    if not info_dirs:
        raise UnsupportedWheel(".dist-info directory not found")

    if len(info_dirs) > 1:
        raise UnsupportedWheel(
            "multiple .dist-info directories found: {}".format(", ".join(info_dirs))
        )

    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

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Inspect: `unzip -l pkg.whl | grep dist-info` — confirm presence.
  2. Rebuild with a standard backend (setuptools/hatchling/flit) which always emits .dist-info.
  3. Re-download from a trusted index and verify hash.
  4. Run `twine check` on the artifact before publishing/installing.

Example fix

// before
# manual zip without metadata
zip -r pkg.whl pkg_module/

// after
# use a real backend so .dist-info is emitted:
python -m build --wheel
Defensive patterns

Strategy: validation

Validate before calling

import zipfile
def has_dist_info(path: str) -> bool:
    with zipfile.ZipFile(path) as z:
        return any(n.split('/',1)[0].endswith('.dist-info') for n in z.namelist())

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: parse_wheel on a zip that has no .dist-info subdir at all. Occurs with renamed plain zips, with wheels whose build backend forgot to emit metadata, or with corrupted/partial wheels.

Common situations: Building a wheel manually without metadata; zip truncated mid-write; .whl extension on a plain archive; third-party packaging tool that omits metadata.

Related errors


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