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

{peer.name}: modern result omitted resultType

Error message

{peer.name}: modern result omitted resultType

What it means

A modern-era request returned a successful result, but the result object lacks the required resultType field. The modern protocol mandates an explicit completion marker; only legacy results get a defaulted 'complete'. Its absence means the server is not conformant with the modern result schema.

Source

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

                request_id,
                method,
                params,
                peer.protocol_version or PROTOCOL_VERSION,
                self.client_capabilities,
            )
        elif peer.era == "legacy":
            message = legacy_request(request_id, method, params)
        else:
            raise RuntimeError(f"{peer.name}: protocol era not selected")
        response = self._send(peer, message)
        if not isinstance(response, dict):
            raise RuntimeError(f"{peer.name}: missing response")
        kind, payload = decode_rpc_response(response, request_id)
        if kind != "result":
            raise RuntimeError(f"{peer.name}: RPC error {payload}")
        result = dict(payload)
        if peer.era == "modern" and "resultType" not in result:
            raise RuntimeError(f"{peer.name}: modern result omitted resultType")
        if peer.era == "legacy":
            result.setdefault("resultType", "complete")
        return result

    def discover_tools(self) -> None:
        for peer_name in sorted(self.peers):
            peer = self.peers[peer_name]
            if peer.available:
                result = self._request(peer, "tools/list", {})
                peer.tools = sorted(result.get("tools", []), key=lambda tool: tool["name"])

    def merge(self, policy: str = "prefix-on-collision") -> None:
        if policy not in {"prefix-on-collision", "reject"}:
            raise ValueError("policy must be prefix-on-collision or reject")
        self.registry.clear()
        for peer_name in sorted(self.peers):
            peer = self.peers[peer_name]
            for tool in peer.tools:

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Inspect the raw result to confirm resultType is missing
  2. Fix the modern server to always include resultType in results
  3. Verify no intermediary strips unknown fields
  4. If the server cannot be fixed, treat it as legacy (allow_legacy) so the default applies

Example fix

// before (server)
return {"jsonrpc": "2.0", "id": rid, "result": {"output": "ok"}}

// after
return {"jsonrpc": "2.0", "id": rid, "result": {"output": "ok", "resultType": "complete"}}
Defensive patterns

Strategy: validation

Validate before calling

null

Type guard

def is_modern_result(result) -> bool:
    return isinstance(result, dict) and 'resultType' in result

Try / catch

try:
    client.call(tool_name, args)
except RuntimeError as e:
    if "omitted resultType" in str(e):
        flag_server_conformance(peer.name)

Prevention

When it happens

Trigger: peer.era == 'modern', decode_rpc_response returned a result dict, and 'resultType' not in result.

Common situations: Modern server build omitting resultType; partial server implementation; a gateway stripping fields from results.

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/9d69de6a5c6e1f07. Report an issue: GitHub.