{"id":"02ca0dd7105eabd7","repo":"pypa/pip","slug":"could-not-read-path-r-file-e-r","errorCode":null,"errorMessage":"could not read {path!r} file: {e!r}","messagePattern":"could not read (.+?) file: (.+?)","errorType":"exception","errorClass":"UnsupportedWheel","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/utils/wheel.py","lineNumber":73,"sourceCode":"    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.\n    \"\"\"\n    path = f\"{dist_info_dir}/WHEEL\"\n    # Zip file path separators must be /\n    wheel_contents = read_wheel_metadata_file(source, path)\n\n    try:\n        wheel_text = wheel_contents.decode()\n    except UnicodeDecodeError as e:\n        raise UnsupportedWheel(f\"error decoding {path!r}: {e!r}\")\n\n    # FeedParser (used by Parser) does not raise any exceptions. The returned\n    # message may have .defects populated, but for backwards-compatibility we\n    # currently ignore them.","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/utils/wheel.py#L55-L91","documentation":"UnsupportedWheel raised by read_wheel_metadata_file when reading a file out of the wheel zip fails. It catches BadZipFile (general corruption), KeyError (entry missing — typically WHEEL or METADATA), and RuntimeError (password-protected zip). The path and the underlying exception repr are surfaced.","triggerScenarios":"wheel_metadata calls source.read('<dist-info>/WHEEL') and the zip is corrupt (BadZipFile), the WHEEL entry is absent (KeyError), or the zip was encrypted (RuntimeError).","commonSituations":"Truncated download producing a structurally invalid zip; wheel that omits the WHEEL file entirely; encrypted/protected zip mislabeled as a wheel; disk corruption.","solutions":["Re-download and verify the hash against the index record.","Inspect integrity: `unzip -t pkg.whl`.","Confirm the .dist-info/WHEEL entry exists: `unzip -l pkg.whl | grep WHEEL`.","Rebuild from clean dist/ if you produced the wheel yourself."],"exampleFix":"// before\npip install ./dist/pkg-1.0.whl   # truncated zip -> BadZipFile\n\n// after\nrm -rf dist && python -m build --wheel && unzip -t dist/pkg-1.0-*.whl && pip install dist/pkg-1.0-*.whl","handlingStrategy":"validation","validationCode":"import zipfile\ndef wheel_zip_intact(path: str) -> bool:\n    try:\n        with zipfile.ZipFile(path) as z:\n            return z.testzip() is None and any(n.endswith('/WHEEL') for n in z.namelist())\n    except (zipfile.BadZipFile, RuntimeError):\n        return False","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Verify hashes after download.","Inspect with `unzip -t` and `unzip -l` in CI.","Don't re-encode/encrypt wheels.","Use trusted transports to avoid truncation."],"tags":["pip","wheel","zip","corruption","metadata"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}