Closed
Description
I have implemented a @GraphQlExceptionHandler
as a coroutine which isn't working as expected.
Details of my setup
java-version
: 17kotlin-version
: 1.8.22spring-boot
: 3.1.1windows
: 11
Details of implementation
When resolving an exception, the framework runs into the following exception:
2023-07-16T00:19:36.161+02:00 WARN 15736 --- [ctor-http-nio-2] a.s.AnnotatedControllerExceptionResolver : Failure while handling exception with public java.lang.Object com.example.graph.NodeController.handle(java.lang.Throwable,graphql.schema.DataFetchingEnvironment,kotlin.coroutines.Continuation<? super graphql.GraphQLError>)
java.lang.ClassCastException: class reactor.core.publisher.MonoOnErrorResume cannot be cast to class graphql.GraphQLError (reactor.core.publisher.MonoOnErrorResume and graphql.GraphQLError are in unnamed module of loader 'app')
at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerExceptionResolver$ReturnValueAdapter.lambda$static$1(AnnotatedControllerExceptionResolver.java:412) ~[spring-graphql-1.2.1.jar:1.2.1]
at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerExceptionResolver$MethodHolder.adapt(AnnotatedControllerExceptionResolver.java:341) ~[spring-graphql-1.2.1.jar:1.2.1]
at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerExceptionResolver.invokeExceptionHandler(AnnotatedControllerExceptionResolver.java:232) ~[spring-graphql-1.2.1.jar:1.2.1]
at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerExceptionResolver.resolveException(AnnotatedControllerExceptionResolver.java:203) ~[spring-graphql-1.2.1.jar:1.2.1]
at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer$SchemaMappingDataFetcher.handleException(AnnotatedControllerConfigurer.java:707) ~[spring-graphql-1.2.1.jar:1.2.1]
at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer$SchemaMappingDataFetcher.lambda$applyExceptionHandling$1(AnnotatedControllerConfigurer.java:696) ~[spring-graphql-1.2.1.jar:1.2.1]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Operators.error(Operators.java:198) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:53) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxFilter$FilterSubscriber.onError(FluxFilter.java:157) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoCreate$DefaultMonoSink.error(MonoCreate.java:201) ~[reactor-core-3.5.7.jar:3.5.7]
at kotlinx.coroutines.reactor.MonoCoroutine.onCancelled(Mono.kt:111) ~[kotlinx-coroutines-reactor-1.6.4.jar:na]
at kotlinx.coroutines.AbstractCoroutine.onCompletionInternal(AbstractCoroutine.kt:91) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:235) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:906) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:863) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:828) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) ~[kotlin-stdlib-1.8.22.jar:1.8.22-release-407(1.8.22)]
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.reactor.MonoKt.monoInternal$lambda-2(Mono.kt:90) ~[kotlinx-coroutines-reactor-1.6.4.jar:na]
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:58) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4561) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.toFuture(Mono.java:5073) ~[reactor-core-3.5.7.jar:3.5.7]
at org.springframework.graphql.execution.ContextDataFetcherDecorator.get(ContextDataFetcherDecorator.java:107) ~[spring-graphql-1.2.1.jar:1.2.1]
at graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:309) ~[graphql-java-20.2.jar:na]
at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:286) ~[graphql-java-20.2.jar:na]
at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:212) ~[graphql-java-20.2.jar:na]
at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:55) ~[graphql-java-20.2.jar:na]
at graphql.execution.Execution.executeOperation(Execution.java:161) ~[graphql-java-20.2.jar:na]
at graphql.execution.Execution.execute(Execution.java:104) ~[graphql-java-20.2.jar:na]
at graphql.GraphQL.execute(GraphQL.java:557) ~[graphql-java-20.2.jar:na]
at graphql.GraphQL.lambda$parseValidateAndExecute$11(GraphQL.java:476) ~[graphql-java-20.2.jar:na]
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2309) ~[na:na]
at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:471) ~[graphql-java-20.2.jar:na]
at graphql.GraphQL.executeAsync(GraphQL.java:439) ~[graphql-java-20.2.jar:na]
at org.springframework.graphql.execution.DefaultExecutionGraphQlService.lambda$execute$2(DefaultExecutionGraphQlService.java:83) ~[spring-graphql-1.2.1.jar:1.2.1]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:47) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2071) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:413) ~[reactor-netty-core-1.1.8.jar:1.1.8]
at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:431) ~[reactor-netty-core-1.1.8.jar:1.1.8]
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:651) ~[reactor-netty-http-1.1.8.jar:1.1.8]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113) ~[reactor-netty-core-1.1.8.jar:1.1.8]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:276) ~[reactor-netty-http-1.1.8.jar:1.1.8]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[netty-codec-4.1.94.Final.jar:4.1.94.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[netty-codec-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.94.Final.jar:4.1.94.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.94.Final.jar:4.1.94.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.94.Final.jar:4.1.94.Final]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
2023-07-16T00:19:36.197+02:00 ERROR 15736 --- [ctor-http-nio-2] s.g.e.ExceptionResolversExceptionHandler : Unresolved NotImplementedError for executionId 525a878c-1
kotlin.NotImplementedError: An operation is not implemented: Not yet implemented, bruh!
at com.example.graph.NodeServiceImpl.node(NodeServiceImpl.kt:15) ~[main/:na]
at com.example.graph.NodeController.node$suspendImpl(NodeController.kt:32) ~[main/:na]
at com.example.graph.NodeController.node(NodeController.kt) ~[main/: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 kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97) ~[kotlin-reflect-1.8.22.jar:1.8.22-release-407(1.8.22)]
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113) ~[kotlin-reflect-1.8.22.jar:1.8.22-release-407(1.8.22)]
at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:107) ~[kotlin-reflect-1.8.22.jar:1.8.22-release-407(1.8.22)]
at kotlin.reflect.full.KCallables.callSuspend(KCallables.kt:56) ~[kotlin-reflect-1.8.22.jar:1.8.22-release-407(1.8.22)]
at org.springframework.core.CoroutinesUtils.lambda$invokeSuspendingFunction$2(CoroutinesUtils.java:108) ~[spring-core-6.0.10.jar:6.0.10]
at kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$4.invokeSuspend(IntrinsicsJvm.kt:205) ~[kotlin-stdlib-1.8.22.jar:1.8.22-release-407(1.8.22)]
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ~[kotlin-stdlib-1.8.22.jar:1.8.22-release-407(1.8.22)]
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:367) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126) ~[kotlinx-coroutines-core-jvm-1.6.4.jar:na]
at kotlinx.coroutines.reactor.MonoKt.monoInternal$lambda-2(Mono.kt:90) ~[kotlinx-coroutines-reactor-1.6.4.jar:na]
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:58) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4561) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Mono.toFuture(Mono.java:5073) ~[reactor-core-3.5.7.jar:3.5.7]
at org.springframework.graphql.execution.ContextDataFetcherDecorator.get(ContextDataFetcherDecorator.java:107) ~[spring-graphql-1.2.1.jar:1.2.1]
at graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:309) ~[graphql-java-20.2.jar:na]
at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:286) ~[graphql-java-20.2.jar:na]
at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:212) ~[graphql-java-20.2.jar:na]
at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:55) ~[graphql-java-20.2.jar:na]
at graphql.execution.Execution.executeOperation(Execution.java:161) ~[graphql-java-20.2.jar:na]
at graphql.execution.Execution.execute(Execution.java:104) ~[graphql-java-20.2.jar:na]
at graphql.GraphQL.execute(GraphQL.java:557) ~[graphql-java-20.2.jar:na]
at graphql.GraphQL.lambda$parseValidateAndExecute$11(GraphQL.java:476) ~[graphql-java-20.2.jar:na]
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2309) ~[na:na]
at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:471) ~[graphql-java-20.2.jar:na]
at graphql.GraphQL.executeAsync(GraphQL.java:439) ~[graphql-java-20.2.jar:na]
at org.springframework.graphql.execution.DefaultExecutionGraphQlService.lambda$execute$2(DefaultExecutionGraphQlService.java:83) ~[spring-graphql-1.2.1.jar:1.2.1]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:47) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2071) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.5.7.jar:3.5.7]
at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:413) ~[reactor-netty-core-1.1.8.jar:1.1.8]
at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:431) ~[reactor-netty-core-1.1.8.jar:1.1.8]
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:651) ~[reactor-netty-http-1.1.8.jar:1.1.8]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113) ~[reactor-netty-core-1.1.8.jar:1.1.8]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:276) ~[reactor-netty-http-1.1.8.jar:1.1.8]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[netty-codec-4.1.94.Final.jar:4.1.94.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[netty-codec-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.94.Final.jar:4.1.94.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.94.Final.jar:4.1.94.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.94.Final.jar:4.1.94.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.94.Final.jar:4.1.94.Final]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
In my controller class I have the following code:
@Controller
class NodeController(
private val nodeService: NodeService
) {
val log: Logger = LoggerFactory.getLogger(NodeController::class.java)
@QueryMapping
suspend fun node(@Argument id: String): Node? {
log.info("Using node id: {}", id)
return nodeService.node(id).awaitSingleOrNull()
}
@QueryMapping
fun nodes(@Argument ids: List<String>): Flow<Node> {
log.info("Using node ids: {}", ids)
return nodeService.nodes(ids).asFlow()
}
@GraphQlExceptionHandler
suspend fun handle(ex: Throwable, env: DataFetchingEnvironment): GraphQLError = coroutineScope {
log.info("Handling error coroutine")
GraphQLError.newError()
.errorType(ErrorType.BAD_REQUEST)
.message(ex.message)
.build()
}
// This works
// @GraphQlExceptionHandler
fun handleT(ex: Throwable, env: DataFetchingEnvironment): GraphQLError {
log.info("Handling error imperative")
return GraphQLError.newError()
.errorType(ErrorType.INTERNAL_ERROR)
.message(ex.message)
.build()
}
// This works as well
// @GraphQlExceptionHandler
fun handleMono(ex: Throwable, env: DataFetchingEnvironment): Mono<GraphQLError> {
log.info("Handling error reactive")
return Mono.just(
GraphQLError.newError()
.errorType(ErrorType.INTERNAL_ERROR)
.message(ex.message)
.build()
)
}
}
I am trying not to mix reactor
code with coroutines
in the same class. And below is the service class intentionally left unimplemented to raise an exception:
@Service
class NodeServiceImpl: NodeService {
override fun node(id: String): Mono<Node> {
TODO("Not yet implemented, bruh!")
}
override fun nodes(ids: List<String>): Flux<Node> {
TODO("Not yet implemented, bruh!")
}
}
with minimalistic schema:
type Query {
node(id: ID!): Node
author(id: ID!): Author
}
interface Node {
id: ID!
}
type Author implements Node{
id: ID!
firstName: String
lastName: String
}
schema {
query: Query
}
Below is a simple query to reproduce the error:
curl 'http://localhost:8080/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' --data-binary '{"query":"query authorDetails($authorId: ID! = \"12345\") {\n node(id: $authorId) {\n id\n __typename\n ... on Author {\n firstName\n lastName\n }\n }\n}\n","variables":{"authorId":"QXV0aG9yOjEyMzQ1Njc4OQo="}}' --compressed
Reproducer
I created a reproducer: GraphQL Demo