Closed
Description
Fethullah Misir opened SPR-17564 and commented
WebClient throws an IllegalStateException with:
Only one connection receive subscriber allowed
when the server response status is 4xx / 5xx.
The issue is not reproducible with Spring Boot 2.1.0.RELEASE / WebFlux 5.1.2.RELEASE.
I reproduced the issue with the test below:
@Test
public void testRetrieveDoesThrowMultipleSubscriberError() {
stubFor( get( urlEqualTo( "/notFound" ) )
.willReturn( aResponse().withHeader( HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE )
.withBody( "{}" )
.withStatus( HttpStatus.NOT_FOUND_404 ) ) );
StepVerifier.create( webClient.get()
.uri( "/notFound" )
.accept( MediaType.APPLICATION_JSON )
.retrieve()
.bodyToMono( String.class ) )
.expectError( WebClientException.class )
.verify();
}
The test pasess, however the below stack trace is logged:
Caused by: java.lang.IllegalStateException: Only one connection receive subscriber allowed.
... 143 common frames omitted
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxMap] :
reactor.core.publisher.Flux.map(Flux.java:5655)
reactor.netty.ByteBufFlux.fromInbound(ByteBufFlux.java:70)
reactor.netty.channel.ChannelOperations.receive(ChannelOperations.java:225)
org.springframework.http.client.reactive.ReactorClientHttpResponse.getBody(ReactorClientHttpResponse.java:64)
org.springframework.web.reactive.function.BodyExtractors.consumeAndCancel(BodyExtractors.java:268)
org.springframework.web.reactive.function.BodyExtractors.lambda$skipBodyAsMono$21(BodyExtractors.java:264)
.....
.....
io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
Error has been observed by the following operator(s):
|_ Flux.map ? reactor.netty.ByteBufFlux.fromInbound(ByteBufFlux.java:70)
|_ Flux.doOnSubscribe ? org.springframework.http.client.reactive.ReactorClientHttpResponse.getBody(ReactorClientHttpResponse.java:65)
I attached a sample, to reproduce the issue.
It seams that the issue is related to the default status handler. When registering a custom one, the stacktrace is not logged and it works as expected.
StepVerifier.create( webClient.get()
.uri( "/notFound" )
.accept( MediaType.APPLICATION_JSON )
.retrieve()
.onStatus( status -> true, response -> Mono.error(IllegalStateException::new ) )
.bodyToMono( String.class ) )
.expectError( IllegalStateException.class )
.verify();
Affects: 5.1.3
Attachments:
- webclient-multi-subscriber.zip (3.42 kB)
Issue Links:
- WebClient .retrieve() + bodyToMono() causes "Only one connection receive subscriber allowed" on 4xx and 5xx [SPR-17615] #22147 WebClient .retrieve() + bodyToMono() causes "Only one connection receive subscriber allowed" on 4xx and 5xx ("is duplicated by")
- WebClient throws "Only one connection receive subscriber allowed." when response generates a WebClientResponseException [SPR-17576] #22108 WebClient throws "Only one connection receive subscriber allowed." when response generates a WebClientResponseException ("is duplicated by")
- The onstatus method of webclient causes a memory leak. [SPR-17473] #22005 The onstatus method of webclient causes a memory leak.
Referenced from: commits 7a5f8e0