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
Description
WebClientStreamableHttpTransport.sendMessage()usesonErrorCompleteto handle errors in the reactive chain that processes HTTP response bodies. When a body-level error occurs (e.g.DataBufferLimitExceptionfrom oversized responses, malformed JSON, SSE parse errors), this operator silently completes the stream. The pendingMcpClientSessionresponse is never resolved, causing the caller to hang untilrequestTimeout(typically 300 seconds).This is the same bug as modelcontextprotocol/java-sdk#889, which was filed against the original
WebClientStreamableHttpTransportbefore it was moved to Spring AI in java-sdk@77bc64a.Root Cause
In
sendMessage(), the reactive chain ends with:onErrorCompleteswallows the error after callingsink.error(t). While the sink is notified, any pending JSON-RPC response inMcpClientSession.pendingResponsesis never resolved because no message reaches the handler.Fix
Change
onErrorCompletetoonErrorResumeand emit a synthetic JSON-RPC error response for requests (not notifications), soMcpClientSessionresolves immediately:Related
HttpClientStreamableHttpTransport(java-sdk main): java-sdk#896