Kotlin Coroutines Exeption Handling

May 12, 2019

Using CoroutineExceptionHandler

val handler = CoroutineExceptionHandler { _, exception ->
    Timber.e(exception, "handler")
}

GlobalScope.launch(Dispatchers.Main + handler) {
    throw Exception("Test")
}

NOTE: Using Timber for Android Logging.

handler will only capture uncaught/unhandled exception. If you surround try/catch as per the example below, handler shall not be called.

GlobalScope.launch(Dispatchers.Main + handler) {
    try {
        throw Exception("Caught")
    }
    catch (e: Exception) {
        Timber.e(e, "catch")
    }

    throw Exception("for handler")
}

Coroutines Stack Trace Caveats

Beaware that coroutines exception handling might not be able to property recover stack trace.

val deferred = GlobalScope.async {
    throw RuntimeException("Test Stacktrace")
}

GlobalScope.launch(Dispatchers.Main + handler) {
    deferred.await()
}

Log

05-13 00:04:36.183 20975-20975/* E/TestFragment$initUi$3$$: handler
    java.lang.RuntimeException: Test Stacktrace
        at *.TestFragment$initUi$3$deferred$1.invokeSuspend(TestFragment.kt:107)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
  • the main clue is TestFragment.kt:107, which point to throw RuntimeException("Test Stacktrace")
  • no indication that throw RuntimeException("Test Stacktrace") is called by deferred.await()
  • another clue is TestFragment$initUi$3$$: handler, indicate the exception happens in initUi function with the message handler.
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.