Skip to content

Error handling no longer works for JSON controller method returning Flux under 6.0.0-M5 #29038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nico-incubiq opened this issue Aug 28, 2022 · 1 comment
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression
Milestone

Comments

@nico-incubiq
Copy link

nico-incubiq commented Aug 28, 2022

Affects: spring-webflux:6.0.0-M5

What I am trying to achieve

I am using Java 17 and spring-webflux:6.0.0-M5, pulled by spring-boot-starter-parent:3.0.0-M4, to build a JSON web API.
One of my controllers returns a Flux<SomeObject>, and when a domain error occurs I trigger an error using something like Flux.error(new ResponseStatusException(HttpStatus.I_AM_A_TEAPOT)).

Expected behaviour

With spring-webflux:6.0.0-M4 and below, when such an error occurs, it is caught by the framework and converted to a web Response like below:

{
    "path": "/working",
    "status": 418,
    "error": "I'm a teapot",
    "timestamp": "2022-08-28T22:29:26.612+00:00",
    "message": null,
    "requestId":"58baedaa"
}

Even under spring-webflux:6.0.0-M5, this mechanism still works for controllers returning a Mono<SomeObject> or a Flux<String> for example, only Flux<SomeObject> is no longer working.

Current behaviour

On controllers returning Flux<SomeObject>, the error signal does not seem to be caught anymore. When calling the app with curl it returns a generic 500 error, and when running JUnit tests an error as below occurs:

reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalStateException: Content has not been consumed, and an error was raised while attempting to produce it.
Caused by: java.lang.IllegalStateException: Content has not been consumed, and an error was raised while attempting to produce it.
	at org.springframework.test.web.reactive.server.WiretapConnector$WiretapRecorder.lambda$getContent$5(WiretapConnector.java:197) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at reactor.core.publisher.Flux.lambda$onErrorMap$27(Flux.java:6901) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at org.springframework.http.server.reactive.ChannelSendOperator$WriteBarrier.emitCachedSignals(ChannelSendOperator.java:302) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
	at org.springframework.http.server.reactive.ChannelSendOperator$WriteBarrier.subscribe(ChannelSendOperator.java:355) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
	at reactor.core.publisher.FluxSource.subscribe(FluxSource.java:67) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Flux.subscribe(Flux.java:8459) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Flux.subscribeWith(Flux.java:8580) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Flux.subscribe(Flux.java:8429) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Flux.subscribe(Flux.java:8353) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Flux.subscribe(Flux.java:8271) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at org.springframework.test.web.reactive.server.WiretapConnector$WiretapRecorder.lambda$getContent$6(WiretapConnector.java:200) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.block(Mono.java:1698) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at org.springframework.test.web.reactive.server.ExchangeResult.formatBody(ExchangeResult.java:292) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at org.springframework.test.web.reactive.server.ExchangeResult.toString(ExchangeResult.java:255) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453) ~[na:na]
	at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:408) ~[na:na]
	at org.springframework.test.web.reactive.server.ExchangeResult.assertWithDiagnostics(ExchangeResult.java:237) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at org.springframework.test.web.reactive.server.StatusAssertions.isEqualTo(StatusAssertions.java:53) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at com.test.ApplicationTest.should_return_418_from_flux_object(ApplicationTest.java:59) ~[test-classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725) ~[junit-platform-commons-1.8.2.jar:1.8.2]
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) ~[junit5-rt.jar:na]
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) ~[junit-rt.jar:na]
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) ~[idea_rt.jar:na]
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) ~[junit-rt.jar:na]
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) ~[junit-rt.jar:na]
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) ~[junit-rt.jar:na]
Caused by: org.springframework.web.server.ResponseStatusException: 418 I_AM_A_TEAPOT
	at com.test.TestController.notWorking(TestController.java:18) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	at org.springframework.web.reactive.result.method.InvocableHandlerMethod.lambda$invoke$0(InvocableHandlerMethod.java:144) ~[spring-webflux-6.0.0-M5.jar:6.0.0-M5]
	at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:152) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:240) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:181) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Operators.complete(Operators.java:137) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:120) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2158) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2194) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2068) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:165) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:87) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribeWith(Mono.java:4387) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4292) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4228) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at org.springframework.test.web.reactive.server.HttpHandlerConnector.lambda$doConnect$2(HttpHandlerConnector.java:100) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at org.springframework.mock.http.client.reactive.MockClientHttpRequest.lambda$writeWith$2(MockClientHttpRequest.java:124) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxConcatIterable$ConcatIterableSubscriber.onComplete(FluxConcatIterable.java:147) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.FluxConcatIterable.subscribe(FluxConcatIterable.java:60) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribeWith(Mono.java:4387) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4292) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4228) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at org.springframework.test.web.reactive.server.HttpHandlerConnector.doConnect(HttpHandlerConnector.java:114) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at org.springframework.test.web.reactive.server.HttpHandlerConnector.lambda$connect$0(HttpHandlerConnector.java:81) ~[spring-test-6.0.0-M5.jar:6.0.0-M5]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4321) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

To me, this looks like the error signal was not caught by the framework and passed down to the WebTestClient rather than converted to a web Response.

Code to replicate

I have set up a sample project on GitHub to replicate the issue, with 2 endpoints which show the expected behaviour and one which shows the erroneous one:
https://github.com/nico-incubiq/webflux-error-replicate/blob/main/src/test/java/com/test/ApplicationTest.java#L19-L35

@nico-incubiq nico-incubiq changed the title Error handling not working for web controllers returning Flux<Object> Error handling no longer working for web controllers returning Flux<Object> under 6.0.0-M5 Aug 28, 2022
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Aug 28, 2022
@rstoyanchev rstoyanchev added this to the Triage Queue milestone Aug 30, 2022
@rstoyanchev rstoyanchev self-assigned this Aug 30, 2022
@rstoyanchev
Copy link
Contributor

rstoyanchev commented Sep 13, 2022

Thanks for the report and sample. This seems to be a regression introduced in 6.0 M5 by #28398.

@rstoyanchev rstoyanchev modified the milestones: Triage Queue, 6.0.0-M6 Sep 13, 2022
@rstoyanchev rstoyanchev added in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 13, 2022
@rstoyanchev rstoyanchev changed the title Error handling no longer working for web controllers returning Flux<Object> under 6.0.0-M5 Error handling no longer works for JSON controller method returning Flux under 6.0.0-M5 Sep 14, 2022
rstoyanchev added a commit that referenced this issue Sep 14, 2022
The test started failing after recent commit
e370c15.

See gh-29038
sbrannen added a commit to sbrannen/spring-framework that referenced this issue Sep 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression
Projects
None yet
Development

No branches or pull requests

3 participants