{"id":"577d57f8b3a44f25","repo":"pypa/pip","slug":"dist-info-directory-info-dir-r-does-not-start-w","errorCode":null,"errorMessage":".dist-info directory {info_dir!r} does not start with {canonical_name!r}","messagePattern":"\\.dist-info directory (.+?) does not start with (.+?)","errorType":"exception","errorClass":"UnsupportedWheel","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/utils/wheel.py","lineNumber":60,"sourceCode":"    # 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\ndef read_wheel_metadata_file(source: ZipFile, path: str) -> bytes:\n    try:\n        return source.read(path)\n        # BadZipFile for general corruption, KeyError for missing entry,\n        # and RuntimeError for password-protected files\n    except (BadZipFile, KeyError, RuntimeError) as e:\n        raise UnsupportedWheel(f\"could not read {path!r} file: {e!r}\")\n\n\ndef wheel_metadata(source: ZipFile, dist_info_dir: str) -> Message:\n    \"\"\"Return the WHEEL metadata of an extracted wheel, if possible.\n    Otherwise, raise UnsupportedWheel.","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/utils/wheel.py#L42-L78","documentation":"UnsupportedWheel raised when the wheel's .dist-info directory name (canonicalized) does not start with the canonicalized wheel/project name. This catches wheels whose metadata directory is misnamed relative to the wheel filename — a sign of tampering or a broken build. The offending info_dir and expected canonical name are both included.","triggerScenarios":"wheel_dist_info_dir finds exactly one .dist-info but its canonicalized name doesn't begin with canonicalize_name(name). For a wheel `Foo-1.0-py3-none-any.whl`, the dir must canonicalize to start with `foo`.","commonSituations":"Wheel renamed after build so filename and metadata dir disagree; backend that normalizes names inconsistently; manually zipped wheel with a typo'd .dist-info dir name; case mismatch (e.g. `Foo` vs `foo`).","solutions":["Inspect the .dist-info dir name with `unzip -l pkg.whl`.","Don't rename wheels after building; rebuild with the correct name.","Use a PEP 517 backend so name canonicalization is consistent between filename and .dist-info.","Confirm the requirement name spelling matches the wheel filename."],"exampleFix":"// before\n# wheel built as Foo but renamed to Bar-1.0-py3-none-any.whl\nmv Foo-1.0-py3-none-any.whl Bar-1.0-py3-none-any.whl\npip install Bar-1.0-py3-none-any.whl\n\n// after\n# rebuild with the correct distribution name:\npython -m build --wheel","handlingStrategy":"validation","validationCode":"import zipfile, re\nfrom pip._vendor.packaging.utils import canonicalize_name  # or packaging.utils\ndef name_matches(path: str) -> bool:\n    wheel_name = os.path.basename(path)[:-4]  # strip .whl\n    project = wheel_name.split('-')[0]\n    canonical = canonicalize_name(project)\n    with zipfile.ZipFile(path) as z:\n        info_dirs = [n.split('/',1)[0] for n in z.namelist() if n.split('/',1)[0].endswith('.dist-info')]\n    return len(info_dirs) == 1 and canonicalize_name(info_dirs[0]).startswith(canonical)","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Never rename wheel files after building.","Use a standard backend so name canonicalization is consistent.","Verify filename spelling against metadata.","Run `twine check`."],"tags":["pip","wheel","metadata","naming","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}