pypa/pip · error · SidecarMetadataInconsistent

Requested has inconsistent Provides-Extra between its PEP…

Error message

Requested {ireq} has inconsistent Provides-Extra 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:333) as SidecarMetadataInconsistent for Provides-Extra. pip compares the set of extras advertised in the sidecar vs the wheel; if they differ it reports the extras only present in each and aborts, because a resolver might offer extras that the wheel cannot actually satisfy.

Solutions

  1. Verify against the official PyPI or a fresh mirror.
  2. Clear the local cache and re-download.
  3. Avoid requesting the missing/extra extra explicitly, or pin a consistent version.
  4. Notify the index operator to fix the sidecar.

Example fix

# before
pip install 'pkg[missing-extra]'
# after: use consistent upstream
pip install --no-cache-dir -i https://pypi.org/simple/ 'pkg[valid-extra]==1.0.0'
Defensive patterns

Strategy: validation

Validate before calling

from email.parser import Parser
import zipfile, io, requests

def _extras_set(msg):
    return frozenset(msg.get_all('Provides-Extra', []))

def sidecar_extras_match(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 _extras_set(m_w) == _extras_set(m_s)

Type guard

def extras_match(sidecar_extras: list[str], wheel_extras: list[str]) -> bool:
    return frozenset(sidecar_extras) == frozenset(wheel_extras)

Try / catch

from subprocess import run
run(["pip", "install", "--no-cache-dir", "-i", "https://pypi.org/simple/", pkg], check=True)

Prevention

When it happens

Trigger: The frozenset of extras from iter_provided_extras() on the sidecar differs from the wheel's. Message shows sidecar-only vs wheel-only extra names.

Common situations: A wheel re-upload added/removed an extra but the mirror's sidecar was not regenerated; index software that drops or reorders extras inconsistently.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/496ea7c631c8992e. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/operations/prepare.py:334

        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:
    """Prepares a Requirement"""

    def __init__(
        self,
        *,
        build_dir: str,
        download_dir: str | None,
        src_dir: str,
        build_isolation: BuildIsolationMode,
        build_isolation_installer: BuildEnvironmentInstaller,

View on GitHub (pinned to f399c37189)