liveBook · Manning

CoroutineExceptionHandler

As explained in Kotlin in Action, 2E

CoroutineExceptionHandler is a coroutine context element that handles uncaught exceptions from root coroutines launched with launch.

CoroutineExceptionHandler is a CoroutineContext element and a last resort for uncaught exceptions from root coroutines launched with launch. Exceptions propagate through the coroutine hierarchy until they meet a supervisor or reach the root; without a handler, the system-wide handler takes over. section 18.3 section 18.6

Attach a handler to a supervised scope

val exceptionHandler = CoroutineExceptionHandler { _, e -> println("[ERROR] ${e.message}") } class ComponentWithScope { private val scope = CoroutineScope( SupervisorJob() + Dispatchers.Default + exceptionHandler ) fun action() = scope.launch { throw UnsupportedOperationException("Ouch!") } } Calling action() produces [ERROR] Ouch!. The handler customizes logging after the root launch fails; it is not a general try-catch mechanism. section 18.3

Apply these rules when placing and using the handler:

  • Place the handler on the root coroutine or its scope. A handler on an intermediate launch does not process a child’s exception when the exception continues upward. section 18.3
  • Use launch for handler-based uncaught-exception processing. If the topmost coroutine uses async, the consumer must handle the exception through await() on the Deferred. section 18.3.1
  • Combine the handler with SupervisorJob when sibling coroutines should continue after one child fails; without supervision, failure can cancel sibling coroutines. section 18.3.1 section 18.6
Listing 18.6 Only the exception handler at the top of the coroutines hierarchy is invoked
import kotlinx.coroutines.*
 
private val topLevelHandler = CoroutineExceptionHandler { _, e ->
    println("[TOP] ${e.message}")
}
 
private val intermediateHandler = CoroutineExceptionHandler { _, e ->
    println("[INTERMEDIATE] ${e.message}")
}
 
@OptIn(DelicateCoroutinesApi::class)    #1
fun main() {
    GlobalScope.launch(topLevelHandler) {
        launch(intermediateHandler) {
            throw UnsupportedOperationException("Ouch!")
        }
    }
    Thread.sleep(1000)
}
// [TOP] Ouch!

Compare root and intermediate handlers in a nested launch hierarchy: only the handler attached to the top-level launch prints [TOP] Ouch!. section 18.3

Listing 18.5 A component with a custom coroutine exception handler
import kotlinx.coroutines.*
import kotlin.time.Duration.Companion.seconds

class ComponentWithScope(dispatcher: CoroutineDispatcher = Dispatchers.Default) {
   private val exceptionHandler = CoroutineExceptionHandler { _, e ->
      println("[ERROR] ${e.message}")
   }

   private val scope = CoroutineScope(
       SupervisorJob() + dispatcher + exceptionHandler
   )

   fun action() = scope.launch {
      throw UnsupportedOperationException("Ouch!")
   }
}


fun main() = runBlocking {
   val supervisor = ComponentWithScope()
   supervisor.action()
   delay(1.seconds)
}

Inspect a complete component that combines SupervisorJob, a dispatcher, and CoroutineExceptionHandler. section 18.3

How Kotlin in Action, 2E covers it

How deep it goes
Explains context placement, hierarchy propagation, supervision, and launch-versus-async behavior, but does not make the handler a catch mechanism.
Examples
Uses custom error logging, a supervised component scope, nested handlers, and an async coroutine whose exception is handled by await().
What it assumes
Assumes coroutine hierarchies, launch, async, await, and coroutine contexts while establishing supervisor behavior and system-handler differences.
What you can do after
Configure it on a root launch or scope, choose supervision for sibling isolation, and route async failures through await().
How it connects
Connects CoroutineExceptionHandler with CoroutineContext, root coroutines, launch, async, await, SupervisorJob, and structured concurrency.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.