pypa/pip · error · CommandError

XMLRPC request failed [code: {fault.faultCode}]\n{fault.faul

Error message

XMLRPC request failed [code: {fault.faultCode}]\n{fault.faultString}

What it means

Raised by SearchCommand.search() when the XML-RPC call to the package index returns an xmlrpc.client.Fault. The fault code and fault string from the remote server are embedded in the message. Most commonly this occurs because PyPI permanently deprecated and disabled its XML-RPC search endpoint, causing every search request to fault server-side.

Source

Thrown at src/pip/_internal/commands/search.py:83

        print_results(hits, terminal_width=terminal_width)
        if pypi_hits:
            return SUCCESS
        return NO_MATCHES_FOUND

    def search(self, query: list[str], options: Values) -> list[dict[str, str]]:
        index_url = options.index

        session = self.get_default_session(options)

        transport = PipXmlrpcTransport(index_url, session)
        pypi = xmlrpc.client.ServerProxy(index_url, transport)
        try:
            hits = pypi.search({"name": query, "summary": query}, "or")
        except xmlrpc.client.Fault as fault:
            message = (
                f"XMLRPC request failed [code: {fault.faultCode}]\n{fault.faultString}"
            )
            raise CommandError(message)
        assert isinstance(hits, list)
        return hits


def transform_hits(hits: list[dict[str, str]]) -> list[TransformedHit]:
    """
    The list from pypi is really a list of versions. We want a list of
    packages with the list of versions stored inline. This converts the
    list from pypi into one we can use.
    """
    packages: dict[str, TransformedHit] = OrderedDict()
    for hit in hits:
        name = hit["name"]
        summary = hit["summary"]
        version = hit["version"]

        if name not in packages.keys():
            packages[name] = {

View on GitHub (pinned to f399c37189)

Solutions

  1. Stop using `pip search`; PyPI no longer supports it. Search via the PyPI website (pypi.org/search) or the JSON API instead.
  2. If using a private/custom index, verify it implements the XML-RPC `search` method.
  3. Check for proxy or TLS interception that could corrupt the XML-RPC response.
  4. For programmatic package discovery, query https://pypi.org/simple/ or the PyPI JSON API (https://pypi.org/pypi/<name>/json).

Example fix

# before (broken on modern PyPI)
pip search requests
# after: use the JSON API
curl -s https://pypi.org/pypi/requests/json | jq '.info.summary'
Defensive patterns

Strategy: fallback

Validate before calling

import urllib.request, json

def search_pypi_json(name: str) -> dict:
    # Reliable alternative to the deprecated XML-RPC search
    with urllib.request.urlopen(f'https://pypi.org/pypi/{name}/json') as r:
        return json.load(r)

Try / catch

try:
    subprocess.run(['pip', 'search', query], check=True)
except subprocess.CalledProcessError:
    # Fallback to the JSON API since PyPI XML-RPC search is deprecated
    result = search_pypi_json(query)

Prevention

When it happens

Trigger: Calling `pip search <query>` against pypi.org (default), or against a custom --index that does not implement the XML-RPC search method, or when a proxy/firewall returns a fault-formatted response.

Common situations: Any modern invocation of `pip search` against PyPI, since PyPI removed XML-RPC search support; using a private index that lacks the search method; intermittent network/proxy issues that corrupt the XML-RPC payload.

Related errors


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