rohitg00/ai-engineering-from-scratch · error · RuntimeError

{peer.name}: proven-modern discovery retry failed

Error message

{peer.name}: proven-modern discovery retry failed

What it means

After a -32022 version hint proved a common version exists, the client resent server/discover with that version and the transport raised TimeoutError or ConnectionError. The retry is bounded by discovery_timeout_ms and fails closed rather than looping.

Source

Thrown at phases/13-tools-and-protocols/08-building-an-mcp-client/code/main.py:457

            if code != -32022:
                raise RuntimeError(f"{peer.name}: correct modern request error {code} before retrying")
            data = payload.get("data")
            advertised = data.get("supported", []) if isinstance(data, dict) else []
            selected = self._mutual_version(advertised)
            if selected is None:
                raise RuntimeError(f"{peer.name}: no mutually supported modern version")
            retry_id = self._new_id()
            retry = modern_request(
                retry_id,
                "server/discover",
                {},
                selected,
                self.client_capabilities,
            )
            try:
                retried = self._send(peer, retry, self.discovery_timeout_ms)
            except (TimeoutError, ConnectionError) as exc:
                raise RuntimeError(f"{peer.name}: proven-modern discovery retry failed") from exc
            if not isinstance(retried, dict):
                raise RuntimeError(f"{peer.name}: proven-modern discovery retry returned no result")
            retry_kind, retry_payload = decode_rpc_response(retried, retry_id)
            if retry_kind != "result":
                raise RuntimeError(f"{peer.name}: proven-modern discovery retry returned an error")
            self._activate_modern(peer, retry_payload, selected)
            return

        self._probe_legacy(peer, f"unrecognized discovery error {code}")

    def connect_all(self) -> None:
        for peer_name in sorted(self.peers):
            self._connect_peer(self.peers[peer_name])

    def _request(self, peer: Peer, method: str, params: dict[str, Any]) -> dict[str, Any]:
        request_id = self._new_id()
        if peer.era == "modern":
            message = modern_request(

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Increase discovery_timeout_ms
  2. Check peer health and connection stability between the two discovery round trips
  3. Look at server logs for a crash or deadlock triggered by the versioned retry
  4. Re-run connect_all once transient network issues are ruled out

Example fix

// before
client = McpClient(..., discovery_timeout_ms=1000)

// after
client = McpClient(..., discovery_timeout_ms=8000)
Defensive patterns

Strategy: retry

Validate before calling

if peer_rtt(peer) > client.discovery_timeout_ms:
    client.discovery_timeout_ms = peer_rtt(peer) * 4

Type guard

null

Try / catch

try:
    client.connect_all()
except RuntimeError as e:
    if "discovery retry failed" in str(e) and transient:  # after fixing cause
        client.connect_all()

Prevention

When it happens

Trigger: self._send(peer, retry, self.discovery_timeout_ms) inside the -32022 retry path raises TimeoutError or ConnectionError.

Common situations: Server accepting the first request then stalling on the retry; connection reset between the two discovery calls; discovery_timeout_ms too tight for a loaded server.

Related errors


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/e93114c41aac0056. Report an issue: GitHub.