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

{peer.name}: legacy initialize returned an error

Error message

{peer.name}: legacy initialize returned an error

What it means

The legacy server answered the initialize probe with a JSON-RPC error response instead of a result. decode_rpc_response matched the request id but classified the message as an error, so the legacy handshake is abandoned with the peer's name attached.

Source

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

        request_id = self._new_id()
        initialize = legacy_request(
            request_id,
            "initialize",
            {
                "protocolVersion": self.supported_legacy[0],
                "capabilities": self.client_capabilities.copy(),
                "clientInfo": CLIENT_INFO.copy(),
            },
        )
        try:
            response = self._send(peer, initialize, self.legacy_probe_timeout_ms)
        except (TimeoutError, ConnectionError) as exc:
            raise RuntimeError(f"{peer.name}: bounded legacy probe failed closed") from exc
        if not isinstance(response, dict):
            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

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Inspect response['error'] to see the server's rejection reason
  2. Verify the legacy_request payload (clientInfo, protocolVersion) matches what the server expects
  3. Check whether the server requires an auth/notification step before initialize
  4. Update or restart the legacy server if its error is spurious

Example fix

// before
try:
    client.connect_all()
except RuntimeError as e:
    pass  # error swallowed, cause unknown

// after
try:
    client.connect_all()
except RuntimeError as e:
    log.error("connect failed: %s", e)  # message includes the RPC error payload
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try:
    client.connect_all()
except RuntimeError as e:
    if "legacy initialize returned an error" in str(e):
        inspect_server_error_log(peer.name)

Prevention

When it happens

Trigger: _probe_legacy receives a valid dict response, decode_rpc_response(response, request_id) returns kind='error', i.e. the payload contains an error object for the initialize request.

Common situations: Legacy server rejecting the clientInfo or protocol parameters; server requiring auth before initialize; method name mismatch between client and an old server build.

Related errors


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