As you have already learned, all coroutines are launched using a coroutine builder (launch, async, and so on). Each of these builders handles exceptions in one of two ways. The first mechanism is designed for when the exception is not exposed to the user, such as with launch. The second mechanism is to re-throw the exception when the user requests the coroutine return value, such as with async.
With the first of these, when an exception is thrown in a coroutine, the parent coroutine is cancelled using that exception. The parent then cancels its children (if there are any other children), and handles the exception when the children have returned. This propagation continues until the global scope is reached, at which point, CoroutineExceptionHandler is used to handle the exception.
A CoroutineExceptionHandler function has two inputs—CoroutineContext and Throwable...