{"id":"e70c7d4079ec78b8","repo":"pypa/pip","slug":"wheel-name-located-at-location-is-invalid","errorCode":null,"errorMessage":"Wheel '{name}' located at {location} is invalid.","messagePattern":"Wheel '(.+?)' located at (.+?) is invalid\\.","errorType":"exception","errorClass":"InvalidWheel","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/metadata/importlib/_dists.py","lineNumber":142,"sourceCode":"        project_name: str,\n    ) -> BaseDistribution:\n        # Generate temp dir to contain the metadata file, and write the file contents.\n        temp_dir = pathlib.Path(\n            TempDirectory(kind=\"metadata\", globally_managed=True).path\n        )\n        metadata_path = temp_dir / \"METADATA\"\n        metadata_path.write_bytes(metadata_contents)\n        # Construct dist pointing to the newly created directory.\n        dist = importlib.metadata.Distribution.at(metadata_path.parent)\n        return cls(dist, metadata_path.parent, None)\n\n    @classmethod\n    def from_wheel(cls, wheel: Wheel, name: str) -> BaseDistribution:\n        try:\n            with wheel.as_zipfile() as zf:\n                dist = WheelDistribution.from_zipfile(zf, name, wheel.location)\n        except zipfile.BadZipFile as e:\n            raise InvalidWheel(wheel.location, name) from e\n        return cls(dist, dist.info_location, pathlib.PurePosixPath(wheel.location))\n\n    @property\n    def location(self) -> str | None:\n        if self._info_location is None:\n            return None\n        return str(self._info_location.parent)\n\n    @property\n    def info_location(self) -> str | None:\n        if self._info_location is None:\n            return None\n        return str(self._info_location)\n\n    @property\n    def installed_location(self) -> str | None:\n        if self._installed_location is None:\n            return None","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/metadata/importlib/_dists.py#L124-L160","documentation":"InvalidWheel raised by Distribution.from_wheel() (importlib backend) when wheel.as_zipfile() fails with zipfile.BadZipFile - the file is named *.whl but is not a valid ZIP archive, so it cannot be opened/read at all. Distinct from UnsupportedWheel (bad contents) in that the file itself is not even a zip.","triggerScenarios":"Reached while preparing a wheel-based distribution: opening the .whl with zipfile raises BadZipFile because the file is truncated, corrupted, or not actually a zip (e.g. an HTML error page saved as .whl, a partial download).","commonSituations":"A truncated download (network drop) leaving an incomplete .whl; a cache (pip cache) containing a corrupted file; a custom index returning an error page with a .whl URL; disk corruption.","solutions":["Clear the pip cache (pip cache purge) and re-download the wheel.","Verify the wheel hash if one is pinned; a mismatch confirms corruption.","Re-download from PyPI directly to rule out a proxy/mirror serving bad files.","If building locally, rebuild and re-export the wheel cleanly."],"exampleFix":"# before - corrupted cached wheel\npip install somepkg\n\n# after\npip cache purge\npip install --no-cache-dir somepkg","handlingStrategy":"validation","validationCode":"import zipfile\ntry:\n    with zipfile.ZipFile(path) as zf:\n        bad = zf.testzip()  # None if OK\n    print('valid zip' if bad is None else f'corrupt entry: {bad}')\nexcept zipfile.BadZipFile:\n    print('not a valid zip / wheel')","typeGuard":"def is_valid_wheel_zip(path: str) -> bool:\n    import zipfile\n    try:\n        with zipfile.ZipFile(path) as zf:\n            return zf.testzip() is None\n    except zipfile.BadZipFile:\n        return False","tryCatchPattern":"from pip._internal.exceptions import InvalidWheel\ntry:\n    dist = Distribution.from_wheel(wheel, name)\nexcept InvalidWheel:\n    # purge cache and re-download\n    ...","preventionTips":["Verify wheel hashes against PyPI before installing.","Clear pip cache when corruption is suspected (pip cache purge).","Re-download with --no-cache-dir to bypass bad cache entries.","Fetch directly from PyPI to avoid mirror/proxy corruption."],"tags":["wheel","zipfile","corruption","cache"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}