pypa/pip · error · SidecarMetadataInconsistent
Requested has inconsistent Requires-Python between its PEP…
Error message
Requested {ireq} has inconsistent Requires-Python between its PEP 658 .metadata file and the wheel's METADATA: sidecar has {f_val!r}, wheel has {m_val!r} What it means
Raised by _check_sidecar_matches_wheel (prepare.py:323) as SidecarMetadataInconsistent for Requires-Python. If the sidecar's Requires-Python field differs from the wheel's, pip aborts because the resolver may have chosen a wheel incompatible with the running interpreter based on stale sidecar data.
Solutions
- Use the official PyPI or a verified mirror.
- Purge local pip cache and retry.
- Pin a version known to be consistent for your interpreter.
- Report the inconsistent metadata to the index operator.
Example fix
# before pip install pkg # after pip install --no-cache-dir -i https://pypi.org/simple/ 'pkg==3.1.2'
Defensive patterns
Strategy: validation
Validate before calling
from email.parser import Parser
import zipfile, io, requests
def sidecar_requires_python_matches(wheel_url: str, sidecar_url: str) -> bool:
wb = requests.get(wheel_url).content
zf = zipfile.ZipFile(io.BytesIO(wb))
m_w = Parser().parsestr(zf.read(next(n for n in zf.namelist() if n.endswith('.dist-info/METADATA'))).decode())
m_s = Parser().parsestr(requests.get(sidecar_url).text)
return (m_w.get('Requires-Python') or '') == (m_s.get('Requires-Python') or '') Type guard
def requires_python_match(sidecar_rp: str | None, wheel_rp: str | None) -> bool:
return (sidecar_rp or '') == (wheel_rp or '') Try / catch
from subprocess import run run(["pip", "install", "--no-cache-dir", "-i", "https://pypi.org/simple/", pkg], check=True)
Prevention
- Use trusted indexes for reproducible installs.
- Purge pip cache when encountering sidecar inconsistencies.
- Ensure your interpreter version is supported by the pinned package version.
When it happens
Trigger: PEP 658 sidecar Requires-Python string differs from the wheel's METADATA Requires-Python string (e.g. '>=3.8' vs '>=3.9').
Common situations: A mirror updated a wheel after a Python-version requirement bump without refreshing the sidecar; inconsistent repackaging of a wheel by a proxy/cache.
Related errors
- Requested has inconsistent Name between its PEP 658…
- Requested has inconsistent Provides-Extra between its PEP…
- Requested has inconsistent Requires-Dist between its PEP…
- Requested has inconsistent Version between its PEP 658…
- Requested has inconsistent Name: expected , but metadata has
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/218fc8919057b4dd.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/operations/prepare.py:324
str(wheel_dist.version),
)
# For multi-use fields, only report the symmetric difference to avoid
# unnecessarily flagging matching values.
sidecar_requires = _canonical_requires(
req, sidecar_dist, "the PEP 658 .metadata file"
)
wheel_requires = _canonical_requires(req, wheel_dist, "the wheel's METADATA")
if sidecar_requires != wheel_requires:
raise SidecarMetadataInconsistent(
req,
"Requires-Dist",
", ".join(sorted(sidecar_requires - wheel_requires)),
", ".join(sorted(wheel_requires - sidecar_requires)),
)
if sidecar_dist.requires_python != wheel_dist.requires_python:
raise SidecarMetadataInconsistent(
req,
"Requires-Python",
str(sidecar_dist.requires_python),
str(wheel_dist.requires_python),
)
sidecar_extras = frozenset(sidecar_dist.iter_provided_extras())
wheel_extras = frozenset(wheel_dist.iter_provided_extras())
if sidecar_extras != wheel_extras:
raise SidecarMetadataInconsistent(
req,
"Provides-Extra",
", ".join(sorted(sidecar_extras - wheel_extras)),
", ".join(sorted(wheel_extras - sidecar_extras)),
)
class RequirementPreparer:View on GitHub (pinned to f399c37189)