When I run this:
fun f() = runBlocking {
val eh = CoroutineExceptionHandler { _, e -> trace("exception handler: $e") }
val j1 = launch(eh) {
trace("launched")
delay(1000)
throw RuntimeException("error!")
}
trace("joining")
j1.join()
trace("after join")
}
f()
This is output:
[main @coroutine#1]: joining
[main @coroutine#2]: launched
java.lang.RuntimeException: error!
at ExceptionHandling$f9$1$j1$1.invokeSuspend(ExceptionHandling.kts:164)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.ResumeModeKt.resumeMode(ResumeMode.kt:67)
According to the documentation for CoroutineExceptionHandler, the eh
handler I provided should be executed. But it's not. Why is that?
I believe the answer lies in this section from the official coroutines docs:
(emphasis mine)
What's described here applies not just to
runBlocking
andGlobalScope
, but any non-top-level coroutine builder and custom scope.To illustrate:
Output:
Note that handler
h1
is executed, buth2
isn't. This is analogous to the handler onGlobalScope#launch
executing, but not the handler provided to anylaunch
insiderunBlocking
.TLDR
Handlers provided to non-root coroutines of a scope will be ignored. A handler provided to the root coroutine will be executed.
As correctly pointed out by Marko Topolnik in the comments below, the above generalization only applies to coroutines created by
launch
. Those created byasync
orproduce
will always ignore all handlers.What is your
kotlinx.coroutines
version? Since 0.26.0 standalonelaunch
builder is now deprecated and You should be usingGlobalScope.launch
instead.I tried your sample and after that change it worked.
Kotlinx.coroutines changelog