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 = capabilitiesView on GitHub (pinned to 39ea8a1c6d)
Solutions
- Inspect response['error'] to see the server's rejection reason
- Verify the legacy_request payload (clientInfo, protocolVersion) matches what the server expects
- Check whether the server requires an auth/notification step before initialize
- 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
- Log full RPC error payloads during integration bring-up
- Verify clientInfo/protocol params the legacy server expects
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
- {peer.name}: unsupported legacy protocol revision
- {peer.name}: malformed legacy initialize result
- {peer.name}: {trigger}; legacy compatibility is not allowlis
- {peer.name}: bounded legacy probe failed closed
- {peer.name}: bounded legacy probe returned no result
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/6b09ca4b790735eb.
Report an issue: GitHub.