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

{peer.name}: malformed legacy initialize result

Error message

{peer.name}: malformed legacy initialize result

What it means

The legacy initialize result passed the version check but its capabilities field is not a dict, or serverInfo is missing/not a dict with non-empty string name and version. The client validates the full legacy result shape before activating the peer and treats a malformed payload as a hard failure.

Source

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

            raise RuntimeError(f"{peer.name}: bounded legacy probe returned no result")
        kind, payload = decode_rpc_response(response, request_id)
        if kind != "result":
            raise RuntimeError(f"{peer.name}: legacy initialize returned an error")
        result = payload
        version = result.get("protocolVersion")
        capabilities = result.get("capabilities")
        server_info = result.get("serverInfo")
        valid_server_info = (
            isinstance(server_info, dict)
            and isinstance(server_info.get("name"), str)
            and bool(server_info["name"])
            and isinstance(server_info.get("version"), str)
            and bool(server_info["version"])
        )
        if version not in self.supported_legacy:
            raise RuntimeError(f"{peer.name}: unsupported legacy protocol revision")
        if not isinstance(capabilities, dict) or not valid_server_info:
            raise RuntimeError(f"{peer.name}: malformed legacy initialize result")
        peer.era = "legacy"
        peer.protocol_version = version
        peer.capabilities = capabilities
        peer.server_info = server_info
        peer.available = True
        self._send(
            peer,
            {"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}
        )

    def _connect_peer(self, peer: Peer) -> None:
        if peer.available and peer.era in {"modern", "legacy"}:
            return
        request_id = self._new_id()
        probe = modern_request(
            request_id,
            "server/discover",
            {},

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Log the raw legacy initialize result and inspect capabilities/serverInfo
  2. Fix the server to return capabilities as an object and serverInfo with non-empty string name and version
  3. If the server is third-party, disable legacy for that peer and require modern discovery

Example fix

// before (server)
result = {"protocolVersion": "2024-11-05", "serverInfo": {"name": "srv", "version": 1}}

// after
result = {"protocolVersion": "2024-11-05", "capabilities": {}, "serverInfo": {"name": "srv", "version": "1.0.0"}}
Defensive patterns

Strategy: validation

Validate before calling

result = dry_run_legacy_initialize(peer)
ok = (isinstance(result.get('capabilities'), dict)
      and isinstance(result.get('serverInfo'), dict)
      and isinstance(result['serverInfo'].get('name'), str)
      and isinstance(result['serverInfo'].get('version'), str))
if not ok:
    fix_server_initialize_result(peer)

Type guard

def valid_legacy_result(result) -> bool:
    return (isinstance(result, dict)
            and isinstance(result.get('capabilities'), dict)
            and isinstance(result.get('serverInfo'), dict)
            and isinstance(result['serverInfo'].get('name'), str)
            and result['serverInfo'].get('name')
            and isinstance(result['serverInfo'].get('version'), str)
            and result['serverInfo'].get('version'))

Try / catch

null

Prevention

When it happens

Trigger: version is in supported_legacy but capabilities is not a dict, or serverInfo fails the isinstance/name/version string checks encoded in valid_server_info.

Common situations: Hand-rolled legacy server returning partial initialize results; serverInfo with numeric version or empty name; capabilities serialized as a list or null by a buggy serializer.

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.

Related errors


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