{"record":{"id":"c35284f9f6a6b972","repo":"pypa/pip","slug":"dist-info-directory-not-found","errorCode":null,"errorMessage":".dist-info directory not found","messagePattern":"\\.dist-info directory not found","errorType":"exception","errorClass":"UnsupportedWheel","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/utils/wheel.py","lineNumber":48,"sourceCode":"\n    check_compatibility(version, name)\n\n    return info_dir, metadata\n\n\ndef wheel_dist_info_dir(source: ZipFile, name: str) -> str:\n    \"\"\"Returns the name of the contained .dist-info directory.\n\n    Raises AssertionError or UnsupportedWheel if not found, >1 found, or\n    it doesn't match the provided name.\n    \"\"\"\n    # Zip file path separators must be /\n    subdirs = {p.split(\"/\", 1)[0] for p in source.namelist()}\n\n    info_dirs = [s for s in subdirs if s.endswith(\".dist-info\")]\n\n    if not info_dirs:\n        raise UnsupportedWheel(\".dist-info directory not found\")\n\n    if len(info_dirs) > 1:\n        raise UnsupportedWheel(\n            \"multiple .dist-info directories found: {}\".format(\", \".join(info_dirs))\n        )\n\n    info_dir = info_dirs[0]\n\n    info_dir_name = canonicalize_name(info_dir)\n    canonical_name = canonicalize_name(name)\n    if not info_dir_name.startswith(canonical_name):\n        raise UnsupportedWheel(\n            f\".dist-info directory {info_dir!r} does not start with {canonical_name!r}\"\n        )\n\n    return info_dir\n\n","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/utils/wheel.py#L30-L66","documentation":"Raised by wheel_dist_info_dir() when the wheel zip contains no top-level subdirectory ending in '.dist-info'. The .dist-info directory holds the wheel's metadata (METADATA, WHEEL, RECORD); its absence means the archive is not a valid wheel per the binary distribution format spec.","triggerScenarios":"Calling wheel_dist_info_dir(source, name) on a ZipFile whose namelist() top-level entries include no directory matching '*.dist-info'. This is reached from parse_wheel() during any wheel installation.","commonSituations":"A zip file renamed to .whl that is not actually a wheel. A wheel built by a broken or incomplete build process that omitted metadata generation. A truncated download missing the metadata entries. A source archive mislabeled as a wheel.","solutions":["Inspect the wheel contents: 'unzip -l <file>.whl' and look for a .dist-info directory","Rebuild the wheel with 'python -m build --wheel' or 'pip wheel'","Re-download from the official index to rule out truncation","If the file is actually a source archive, install it as a tarball/zip, not as a wheel"],"exampleFix":"// before\npip install ./myproj-1.0-py3-none-any.whl  # zip renamed to .whl\n// after\n# build a proper wheel with metadata\npython -m build --wheel\npip install dist/myproj-1.0-py3-none-any.whl","handlingStrategy":"validation","validationCode":"import zipfile\n\ndef wheel_has_dist_info(path: str) -> bool:\n    try:\n        with zipfile.ZipFile(path) as zf:\n            top_dirs = {n.split('/')[0] for n in zf.namelist() if '/' in n}\n            return any(d.endswith('.dist-info') for d in top_dirs)\n    except (zipfile.BadZipFile, FileNotFoundError):\n        return False\n\n# before installing\nif not wheel_has_dist_info(wheel_path):\n    raise ValueError(f'{wheel_path} is missing a .dist-info directory')","typeGuard":"import zipfile\n\ndef has_single_dist_info(zf: zipfile.ZipFile) -> bool:\n    dirs = {n.split('/')[0] for n in zf.namelist() if '/' in n}\n    return sum(1 for d in dirs if d.endswith('.dist-info')) == 1","tryCatchPattern":"from pip._internal.exceptions import UnsupportedWheel\n\ntry:\n    wheel_dist_info_dir(wheel_zip, name)\nexcept UnsupportedWheel as e:\n    if '.dist-info directory not found' in str(e):\n        raise PackagingError(f'wheel is not a valid distribution: {e}')\n    raise","preventionTips":["Build wheels with compliant backends that always generate .dist-info","Verify wheel structure with 'unzip -l' before installing","Do not rename non-wheel zips to .whl","Re-download from the official index"],"tags":["wheel","metadata","dist-info","packaging","installation"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}