Skip to content

WebClientStreamableHttpTransport silently drops body-level errors #5775

@Planview-JamesK

Description

@Planview-JamesK

Description

WebClientStreamableHttpTransport.sendMessage() uses onErrorComplete to handle errors in the reactive chain that processes HTTP response bodies. When a body-level error occurs (e.g. DataBufferLimitException from oversized responses, malformed JSON, SSE parse errors), this operator silently completes the stream. The pending McpClientSession response is never resolved, causing the caller to hang until requestTimeout (typically 300 seconds).

This is the same bug as modelcontextprotocol/java-sdk#889, which was filed against the original WebClientStreamableHttpTransport before it was moved to Spring AI in java-sdk@77bc64a.

Root Cause

In sendMessage(), the reactive chain ends with:

.onErrorComplete(t -> {
    this.handleException(t);
    sink.error(t);
    return true;
})

onErrorComplete swallows the error after calling sink.error(t). While the sink is notified, any pending JSON-RPC response in McpClientSession.pendingResponses is never resolved because no message reaches the handler.

Fix

Change onErrorComplete to onErrorResume and emit a synthetic JSON-RPC error response for requests (not notifications), so McpClientSession resolves immediately:

.onErrorResume(t -> {
    this.handleException(t);
    sink.error(t);
    if (requestId != null) {
        McpSchema.JSONRPCResponse errorResponse = new McpSchema.JSONRPCResponse(
            McpSchema.JSONRPC_VERSION, requestId, null,
            new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR,
                "Transport error during response streaming: " + t.getMessage(), null));
        return this.handler.get().apply(Mono.just(errorResponse));
    }
    return Flux.empty();
})

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions