GRpcExceptionHandler doesn't work [Kotlin]
Hi, thanks for the work you've done. It's really great starter!
I have some trouble, maybe it related with Kotlin CoroutineImpl. The interceptor below does not catch exception:
@GRpcService
class TempUrlService() : TempUrlServiceGrpcKt.TempUrlServiceCoroutineImplBase() {
private val logger = KotlinLogging.logger {}
@GRpcExceptionHandler
fun anotherHandler(e: NullPointerException, scope: GRpcExceptionScope): Status {
logger.warn { "NPE!" }
return Status.INTERNAL
}
@Throws(Throwable::class)
override suspend fun createThumbnailTempUrl(request: ThumbRequest): ThumbResponse {
throw NullPointerException("HELLO")
}
}
Using 4.5.10 version.
Can you please try to debug to see the private handler discovered here for your TempUrlService service bean ?
The actual handler then resolved here
@jvmlet
My handler are presented, but method resolveMethodByThrowable isn't invoked.
I could not find the entry point where interceptor should be invoked :(
for unary call it's called from here
Ohh, I think the issue is this line , I should also check the privateResolvers
Meanwhile, please add dummy global handler as temporary workaround to proceed here ..
Hi, do you mean GRpcServiceAdvice or GRpcGlobalInterceptor ?
First doesn't work too for me

While I wrapped in try..catch :)
The problem is this line , it should check private resolvers as well. So, meanwhile, you can workaround the bug by adding dummy @GRpcServiceAdvice with @GRpcServiceAdvice method, it will force interceptor to proceed (here) and you private handler should be invoked
Please tell, is code ok?
Exception
class TestException(message: String) : Exception(message)
Service
@GRpcService
class FileService() : FileServiceGrpcKt.FileServiceCoroutineImplBase() {
override suspend fun getInfo(request: FileInfoRequest): FileInfoResponse {
throw TestException("Hello")
}
}
Advice
@GRpcServiceAdvice
class GRpcErrorInterceptor {
private val logger = KotlinLogging.logger {}
@GRpcExceptionHandler
fun throwableExceptionHandler(e: TestException, scope: GRpcExceptionScope): Status {
logger.error(e) { "gRPC unexpected error" }
return Status.INTERNAL.withCause(e) // should be code 13
}
}
But no logs in application, and status differs:
hett@STORM:~ $ grpc_cli call 172.23.0.1:9090 getInfo ""
connecting to 172.23.0.1:9090
Rpc failed with status code 2, error message:
I can provide demo app.
Hmmm, I suspected that the problem is in the coroutines, but not. This doesn't work too:
@GRpcService()
class FileService() : FileServiceGrpc.FileServiceImplBase() {
private val logger = KotlinLogging.logger {}
override fun getInfo(request: FileInfoRequest, responseObserver: StreamObserver<FileInfoResponse>) {
throw TestException("Hello")
}
}
You should have both @GRpcExceptionHandler : global and private. Your private handler will be called
You also should wrap your exception with throw new GRpcRuntimeExceptionWrapper(new TestException(),"myHint"), the RuntimeException is caught...
Bingo, with runtime exception it is works!
The problem is that the Kotlin does not have throws signature and not differs checked/non-checked exceptions. In may case I testing java checked exception.
If declared next exception, no any logs will produced on error and it big problem:
class TestException(message: String) : java.lang.Exception(message)
The next code with runtime exception works (global handler registered too):
class TestException(message: String) : java.lang.RuntimeException(message)
@GRpcService()
class FileService() : FileServiceGrpc.FileServiceImplBase() {
@GRpcExceptionHandler
fun anotherHandler(e: TestException, scope: GRpcExceptionScope): Status {
logger.warn { "error!" }
return Status.INTERNAL
}
override fun getInfo(request: FileInfoRequest, responseObserver: StreamObserver<FileInfoResponse>) {
throw TestException("Hello")
}
}
But if trying to extend kotlin corutine impl we get silence again in the logs :(
@GRpcService()
class FileService() : FileServiceGrpcKt.FileServiceCoroutineImplBase() {
@GRpcExceptionHandler
fun anotherHandler(e: TestException, scope: GRpcExceptionScope): Status {
logger.warn { "error!" }
return Status.INTERNAL
}
override suspend fun getInfo(request: FileInfoRequest): FileInfoResponse {
throw TestException("Hello")
}
}
I suspect that it is different troubles.
I created demo project which reproduces both problems https://github.com/TheHett/grpc_demo/tree/master/src/main/kotlin/com/example/demo/grpc
It should be call manually because I doesn't know how to write test for this
grpc_cli call 127.0.0.1:6565 demo.api.DemoService/test ""
You can have a look at demo module in this repo to get the idea how to develop unit tests
Hi, It doesn't works for me as for @TheHett. I have checked methodResolver attribute content inside the GRpcExceptionHandlerInterceptor after its initialisation through the constructor. It contains as expected in the mapperHandlers the @GRpcExceptionHandler method defined inside @GRpcServiceAdvice classes, and each grpc services (privateResolvers) contains to their @GRpcExceptionHandler method inside its respective mapperHandlers attribute.
At runtime, when I look at this condition for check global exception handler (declared via @GRpcServiceAdvice) it's return true but when I throw the exception (runtimeEx or not) it's not cached, and when I look too the same place for local exception handler (from @GrpcService) it's return false, and btw exception are not cached too.
Ps: for test with exception, i did used the wrapper as doc advices it.
@jvmlet have you an idea about how I could work around this issue please ?
Any idea @jvmlet please ?
i have the same problem with kotlin, @GrpcExceptionHandler in service or @GRpcServiceAdvice on single class doesn't work
Still relevant with 4.9.1, any updates here?
Fixed in latest 5.1.5-SNAPSHOT, please verify and confirm.
5.1.5 was released
I am still getting it in 5.1.5
Maybe it's somehow interfere with the order of interceptors?
grpc.security.auth.interceptor-order=-4
grpc.recovery.interceptor-order=-2
grpc.validation.interceptor-order=-1