You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A GraphQL Subscription with an input field that is annotated with a validation directive gets called with an input parameter that conflicts with the validation directive.
The ExecutionResult contains the correct validation error specified for the directive.
Actual behavior
A GraphQL Subscription with an input field that is annotated with a validation directive gets called with an input parameter that conflicts with the validation directive.
The ExecutionResult contains the following error: java.lang.IllegalStateException: Expected Publisher for a subscription
Steps to reproduce
Have a GraphQL Subscription with an input field that is annotated with a validation directive.
E.g.:
I created a test case where I checked for the correct behavior of the validations. On a mutation it works as expected and when the input parameter conforms with the validation on a Subscription there is also no issue.
I hope anyone can help me figuring out the problem here.
When you clone my test repo and try it out yourself you'll see that the third test fails.
@TestvoidsubscribeToPostsWithInvalidInput() {
Stringquery = "subscription subscribeToPosts($title: String!){ subscribeToPosts(title: $title) }";
Map<String, Object> variables = Map.of("title", "test"); // conflict with @Size directiveExecutionResultexecutionResult = dgsQueryExecutor.execute(query, variables);
assertThat(executionResult.getErrors()).isNotEmpty();
assertThat(Optional.ofNullable(executionResult.getData())).isEmpty();
assertThat(executionResult.getErrors().get(0).getMessage())
.isEqualTo("/subscribeToPosts/title size must be between 5 and 50");
}
While debugging, setting a breakpoint for any IllegalStateExceptions, you can see that the expected error message can be found in a DataFetcherResult in the ReactiveAdapterRegistryHelper.
In the end however, the IllegalStateException is thrown by the ReactiveAdapter being null.
publicabstractclassReactiveAdapterRegistryHelper {
//.../** * Return a {@link Flux} for the given result Object, adapting to a * {@link Publisher} first if necessary via {@link ReactiveAdapterRegistry}. * @param result the result Object to adapt * @return a {@link Flux}, possibly empty if the result is {@code null} */publicstaticFlux<?> toSubscriptionFlux(@NullableObjectresult) {
if (result == null) {
returnFlux.empty();
}
if (resultinstanceofPublisher<?> publisher) {
returnFlux.from(publisher);
}
ReactiveAdapteradapter = registry.getAdapter(result.getClass());
Assert.state(adapter != null, "Expected Publisher for a subscription");
returnFlux.from(adapter.toPublisher(result));
}
//...
}
Here is the console output for that test:
2025-02-13T11:49:01.765+01:00 ERROR 30488 --- [ Test worker] g.d.e.DefaultDataFetcherExceptionHandler : Exception while executing data fetcher for /subscribeToPosts: Expected Publisher for a subscription
java.lang.IllegalStateException: Expected Publisher for a subscription
at org.springframework.util.Assert.state(Assert.java:79) ~[spring-core-6.2.2.jar:6.2.2]
at org.springframework.graphql.execution.ReactiveAdapterRegistryHelper.toSubscriptionFlux(ReactiveAdapterRegistryHelper.java:105) ~[spring-graphql-1.3.3.jar:1.3.3]
at org.springframework.graphql.execution.ContextDataFetcherDecorator.get(ContextDataFetcherDecorator.java:90) ~[spring-graphql-1.3.3.jar:1.3.3]
at graphql.execution.instrumentation.dataloader.FallbackDataLoaderDispatchStrategy.lambda$modifyDataFetcher$0(FallbackDataLoaderDispatchStrategy.java:25) ~[graphql-java-22.3.jar:na]
at graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:533) ~[graphql-java-22.3.jar:na]
at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:497) ~[graphql-java-22.3.jar:na]
at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:438) ~[graphql-java-22.3.jar:na]
at graphql.execution.SubscriptionExecutionStrategy.createSourceEventStream(SubscriptionExecutionStrategy.java:110) ~[graphql-java-22.3.jar:na]
at graphql.execution.SubscriptionExecutionStrategy.execute(SubscriptionExecutionStrategy.java:67) ~[graphql-java-22.3.jar:na]
at graphql.execution.Execution.executeOperation(Execution.java:181) ~[graphql-java-22.3.jar:na]
at graphql.execution.Execution.execute(Execution.java:117) ~[graphql-java-22.3.jar:na]
at graphql.GraphQL.execute(GraphQL.java:546) ~[graphql-java-22.3.jar:na]
at graphql.GraphQL.lambda$parseValidateAndExecute$13(GraphQL.java:476) ~[graphql-java-22.3.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-22.3.jar:na]
at graphql.GraphQL.lambda$executeAsync$9(GraphQL.java:429) ~[graphql-java-22.3.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.executeAsync(GraphQL.java:418) ~[graphql-java-22.3.jar:na]
at org.springframework.graphql.execution.DefaultExecutionGraphQlService.lambda$execute$2(DefaultExecutionGraphQlService.java:104) ~[spring-graphql-1.3.3.jar:1.3.3]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:47) ~[reactor-core-3.6.1.jar:3.6.1]
at reactor.core.publisher.Mono.subscribe(Mono.java:4512) ~[reactor-core-3.6.1.jar:3.6.1]
at reactor.core.publisher.Mono.block(Mono.java:1727) ~[reactor-core-3.6.1.jar:3.6.1]
at com.netflix.graphql.dgs.springgraphql.SpringGraphQLDgsQueryExecutor.execute(SpringGraphQLDgsQueryExecutor.kt:90) ~[graphql-dgs-spring-graphql-10.0.3.jar:10.0.3]
at com.netflix.graphql.dgs.DgsQueryExecutor.execute(DgsQueryExecutor.java:59) ~[graphql-dgs-10.0.3.jar:10.0.3]
at com.example.graphqlextendedvalidationissue.GraphqlExtendedValidationIssueApplicationTests.subscribeToPostsWithInvalidInput(GraphqlExtendedValidationIssueApplicationTests.java:79) ~[test/: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:569) ~[na:na]
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:767) ~[junit-platform-commons-1.11.4.jar:1.11.4]
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$8(TestMethodTestDescriptor.java:217) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68) ~[junit-jupiter-engine-5.11.4.jar:5.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:156) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) ~[junit-platform-engine-1.11.4.jar:1.11.4]
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.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:160) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) ~[junit-platform-engine-1.11.4.jar:1.11.4]
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.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:160) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[junit-platform-engine-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) ~[junit-platform-launcher-1.11.4.jar:1.11.4]
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:124) ~[na:na]
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:99) ~[na:na]
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:94) ~[na:na]
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:63) ~[na: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:569) ~[na:na]
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) ~[na:na]
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) ~[na:na]
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) ~[na:na]
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:92) ~[na:na]
at jdk.proxy1/jdk.proxy1.$Proxy4.stop(Unknown Source) ~[na:na]
at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:200) ~[na:na]
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:132) ~[na:na]
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103) ~[na:na]
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63) ~[na:na]
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) ~[na:na]
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:121) ~[na:na]
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71) ~[na:na]
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) ~[gradle-worker.jar:na]
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) ~[gradle-worker.jar:na]
Expected :"/subscribeToPosts/title size must be between 5 and 50"
Actual :"java.lang.IllegalStateException: Expected Publisher for a subscription"
<Click to see difference>
org.opentest4j.AssertionFailedError:
expected: "/subscribeToPosts/title size must be between 5 and 50"
but was: "java.lang.IllegalStateException: Expected Publisher for a subscription"
at com.example.graphqlextendedvalidationissue.GraphqlExtendedValidationIssueApplicationTests.subscribeToPostsWithInvalidInput(GraphqlExtendedValidationIssueApplicationTests.java:84)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
The text was updated successfully, but these errors were encountered:
Prototype-42
changed the title
bug: graphql-dgs-extended-validation returns IllegalStateException in ExecutionResult of GraphQL Subscription
bug: graphql-dgs-extended-validation returns IllegalStateException instead of validation exception in ExecutionResult of GraphQL Subscription
Feb 13, 2025
Expected behavior
Actual behavior
java.lang.IllegalStateException: Expected Publisher for a subscription
Steps to reproduce
Have a GraphQL Subscription with an input field that is annotated with a validation directive.
E.g.:
Then call the Subscription with an input parameter that conflicts with the validation directive.
E.g.:
Test case
GitHub Link
I created a test case where I checked for the correct behavior of the validations. On a mutation it works as expected and when the input parameter conforms with the validation on a Subscription there is also no issue.
I hope anyone can help me figuring out the problem here.
When you clone my test repo and try it out yourself you'll see that the third test fails.
While debugging, setting a breakpoint for any IllegalStateExceptions, you can see that the expected error message can be found in a
DataFetcherResult
in theReactiveAdapterRegistryHelper
.In the end however, the IllegalStateException is thrown by the
ReactiveAdapter
beingnull
.Here is the console output for that test:
The text was updated successfully, but these errors were encountered: