conductor-oss/conductor · error · RuntimeException

Invalid JSON-RPC response: missing 'result' field

Error message

Invalid JSON-RPC response: missing 'result' field

What it means

Thrown by listToolsDirectHttp when the JSON-RPC response has neither an `error` nor a `result` field. Per JSON-RPC 2.0 a valid response to a request must contain exactly one of result/error; absence of both means the server returned a structurally non-conformant payload (e.g. just an ack, or an SSE event that was not a JSON-RPC response).

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/mcp/MCPService.java:154

            String contentType = response.contentType;

            // Parse response based on content type
            JsonNode responseJson;
            if (contentType != null && contentType.contains("text/event-stream")) {
                // Parse SSE format
                responseJson = parseSseResponse(responseBody);
            } else {
                // Parse as JSON directly
                responseJson = objectMapper.readTree(responseBody);
            }

            if (responseJson.has("error")) {
                throw new RuntimeException(
                        "JSON-RPC error: " + responseJson.get("error").toString());
            }

            if (!responseJson.has("result")) {
                throw new RuntimeException("Invalid JSON-RPC response: missing 'result' field");
            }

            JsonNode result = responseJson.get("result");
            JsonNode toolsNode = result.get("tools");

            if (toolsNode == null || !toolsNode.isArray()) {
                throw new RuntimeException(
                        "Invalid response: 'tools' field is missing or not an array");
            }
            ExternalDataLimits.validateStructure(objectMapper.convertValue(result, Object.class));

            // Convert to McpSchema.Tool list
            // Use Jackson to deserialize tools directly (same pattern as stdio implementation)
            List<McpSchema.Tool> tools =
                    objectMapper.convertValue(
                            toolsNode,
                            objectMapper
                                    .getTypeFactory()

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Capture the raw response body to confirm what the server actually returned (it was logged at debug).
  2. Verify the endpoint is a JSON-RPC responder and not an event-stream info endpoint.
  3. Ensure the Accept header negotiated a transport the server uses to send the JSON-RPC result back.
  4. If the server only speaks SSE, confirm content-type detection worked so parseSseResponse was invoked.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    mcpService.listTools(serverUrl, headers);
} catch (RuntimeException e) {
    if (e.getMessage().contains("missing 'result' field")) {
        // server returned a non-JSON-RPC envelope; log body and check endpoint/transport
    }
    throw e;
}

Prevention

When it happens

Trigger: Server returns `{"jsonrpc":"2.0","id":1}` with no result/error; server returns a notification-style or progress message as the response; SSE stream delivered only keep-alive/event frames and no data payload that resolved to a JSON-RPC response object.

Common situations: Hitting a server that streams server-sent events where the first non-data frames were concatenated; pointing at an endpoint that returns metadata instead of a JSON-RPC response; mismatched transport expectation (server is SSE-only but content-type was not text/event-stream).

Understand the failure class

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/dd68b2c55a271035. Report an issue: GitHub.