spring-projects / spring-graphql

Spring Integration for GraphQL
https://spring.io/projects/spring-graphql
Apache License 2.0
1.54k stars 306 forks source link

Error thrown in custom handler fails #1090

Open Sam-Kruglov opened 4 days ago

Sam-Kruglov commented 4 days ago

If my handler throws an error, then DataFetcherHandlerMethod (line 239) returns Mono.error(..), and then AnnotatedControllerExceptionResolver (line 241) tries to convert it to Mono again, which gives ClassCastException

https://github.com/spring-projects/spring-graphql/blob/381c9f3cc06ed2c0dfd102d647b0d2feb2a4bd06/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerExceptionResolver.java#L239-L241

Specifically, in my case I see I threw an error from my handler @GraphQlExceptionHandler fun handle(...): List<GraphQLError> {...} that ended up here:

doInvoke:129, InvocableHandlerMethodSupport (org.springframework.graphql.data.method)
validateAndInvoke:142, DataFetcherHandlerMethod (org.springframework.graphql.data.method.annotation.support)
invoke:125, DataFetcherHandlerMethod (org.springframework.graphql.data.method.annotation.support)
invokeExceptionHandler:239, AnnotatedControllerExceptionResolver (org.springframework.graphql.data.method.annotation.support)
resolveException:211, AnnotatedControllerExceptionResolver (org.springframework.graphql.data.method.annotation.support)

After that, the Mono.error with my exception is attempted to be cast to the return type of my handler here: https://github.com/spring-projects/spring-graphql/blob/381c9f3cc06ed2c0dfd102d647b0d2feb2a4bd06/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerExceptionResolver.java#L444-L449

Line 446 evaluates to false because it is instance of Mono and it tried to cast it to Collection<GraphQLError> and then fails.

And finally, I don't even get to see my actual error that got thrown in my exception handler in the logs, all I can see are these:

42:57.187 WARN --- [xec-7] a.s.AnnotatedControllerExceptionResolver: Failure while handling exception with *handler signature*
java.lang.ClassCastException...
42:57.189 WARN --- [xec-7] a.s.AnnotatedControllerExceptionResolver: Failure while handling exception with *handler signature*
java.lang.ClassCastException... --- why print the same log AGAIN?
42:57.190 WARN  --- [xec-7] s.g.e.ExceptionResolversExceptionHandler: Failure while resolving *resolver signature*
jakarta.validation.ConstraintViolationException... ---- error that got thrown in the code and that I was trying to handle
bclozel commented 3 days ago

Thanks for the analysis but you are one step ahead of us. Can you show a minimal error handler code snippet that would trigger this so we can have a look?

Sam-Kruglov commented 2 days ago

Just throw any error. I believe it doesn't matter how you get to the exception handler, only matters that the handler itself throws an error.

@GraphQlExceptionHandler
fun handle(ex: ConstraintViolationException, env: DataFetchingEnvironment): List<GraphQLError> {
   throw IllegalStateException("oops")
}