rohitg00/ai-engineering-from-scratch · error · RuntimeError
{peer.name}: malformed modern discovery result
Error message
{peer.name}: malformed modern discovery result What it means
The peer answered server/discover with a result, but its supportedVersions field is not a list of strings. The client requires an explicit, well-typed version advertisement before it can pick a mutually supported revision.
Source
Thrown at phases/13-tools-and-protocols/08-building-an-mcp-client/code/main.py:430
)
try:
response = self._send(peer, probe, self.discovery_timeout_ms)
except (TimeoutError, ConnectionError) as exc:
self._probe_legacy(peer, type(exc).__name__)
return
if response is None:
self._probe_legacy(peer, "empty discovery response")
return
if not isinstance(response, dict):
raise RuntimeError(f"{peer.name}: malformed discovery response")
kind, payload = decode_rpc_response(response, request_id)
if kind == "result":
advertised = payload.get("supportedVersions", [])
if not isinstance(advertised, list) or not all(
isinstance(version, str) for version in advertised
):
raise RuntimeError(f"{peer.name}: malformed modern discovery result")
selected = self._mutual_version(advertised)
if selected is None:
raise RuntimeError(f"{peer.name}: no mutually supported modern version")
self._activate_modern(peer, payload, selected)
return
code = payload["code"]
if code in RECOGNIZED_MODERN_ERRORS:
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,View on GitHub (pinned to 39ea8a1c6d)
Solutions
- Log the discovery result and inspect supportedVersions
- Fix the server to emit supportedVersions as an array of version strings
- Validate the server build against the modern discovery schema
Example fix
// before (server)
{"supportedVersions": ["1.1", 1.2]}
// after
{"supportedVersions": ["1.1", "1.2"]} Defensive patterns
Strategy: validation
Validate before calling
adv = probe_supported_versions(peer)
if not (isinstance(adv, list) and all(isinstance(v, str) for v in adv)):
fix_server_discovery_payload(peer) Type guard
def valid_version_advertisement(v) -> bool:
return isinstance(v, list) and all(isinstance(x, str) for x in v) Try / catch
null
Prevention
- Contract-test server/discover responses
- Serialize versions as strings end to end
When it happens
Trigger: decode_rpc_response returns kind='result' and payload.get('supportedVersions') is not a list, or contains entries that are not str.
Common situations: Server serializing versions as numbers or nulls; a typo'd field in a custom server build; a discovery payload built by hand in tests.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- server/discover accepts no params beyond _meta
- {peer.name}: malformed legacy initialize result
- {peer.name}: malformed discovery response
- {peer.name}: no mutually supported modern version
- {peer.name}: correct modern request error {code} before retr
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/d863b744b185ff8c.
Report an issue: GitHub.