pypa/pip · error · UnsupportedWheel
multiple .dist-info directories found
Error message
multiple .dist-info directories found: {} What it means
Raised by wheel_dist_info_dir() when the wheel zip contains more than one top-level '.dist-info' directory. A valid wheel must contain exactly one .dist-info directory; multiple indicate a malformed or merged archive.
Solutions
- List the wheel contents: 'unzip -l <file>.whl' and identify the multiple .dist-info entries
- Rebuild the wheel cleanly from source with 'python -m build --wheel'
- Re-download the wheel from the official PyPI index
- If you control the build, ensure only one distribution's metadata is emitted per wheel
Example fix
// before pip install ./merged-1.0-py3-none-any.whl # contains two .dist-info dirs // after # rebuild a single clean wheel python -m build --wheel --no-isolation pip install dist/merged-1.0-py3-none-any.whl
Defensive patterns
Strategy: validation
Validate before calling
import zipfile
def wheel_has_single_dist_info(path: str) -> bool:
with zipfile.ZipFile(path) as zf:
dirs = {n.split('/')[0] for n in zf.namelist() if '/' in n}
return sum(1 for d in dirs if d.endswith('.dist-info')) == 1 Type guard
import zipfile
def has_exactly_one_dist_info(zf: zipfile.ZipFile) -> bool:
dirs = {n.split('/')[0] for n in zf.namelist() if '/' in n}
return sum(1 for d in dirs if d.endswith('.dist-info')) == 1 Try / catch
from pip._internal.exceptions import UnsupportedWheel
try:
wheel_dist_info_dir(wheel_zip, name)
except UnsupportedWheel as e:
if 'multiple .dist-info' in str(e):
raise PackagingError(f'wheel contains multiple distributions: {e}')
raise Prevention
- Build one wheel per distribution with a standard backend
- Never manually merge wheel archives
- Verify with 'unzip -l <file>.whl' that only one .dist-info exists
- Re-download from the official index
When it happens
Trigger: Calling wheel_dist_info_dir(source, name) where the set of top-level namelist entries contains two or more names ending in '.dist-info'. Reached during any wheel installation via parse_wheel().
Common situations: Two wheels manually zipped together. A build tool bug that emits metadata for multiple distributions into one wheel. A wheel repackaging tool that concatenated archives. A corrupted index serving a merged artifact.
Related errors
- .dist-info directory not found
- .dist-info directory
- invalid Wheel-Version
- has an invalid wheel
- WHEEL is missing Wheel-Version
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/9c558818c12188a6.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/utils/wheel.py:51
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
def read_wheel_metadata_file(source: ZipFile, path: str) -> bytes:
try:
return source.read(path)View on GitHub (pinned to f399c37189)