Vasiliy
Vasiliy

Reputation: 16228

CoroutineExceptionHandler "swallows" exceptions, but handleException() function isn't called

When I execute this unit test I see exception notification in the output (probably default exception handler prints it):

@Test
fun uncaughtException() {
    runBlocking {
        val scope = CoroutineScope(Dispatchers.Default)
        val job = scope.launch() {
            delay(100)
            println("inside coroutine")
        }
        scope.launch {
            delay(50)
            throw Exception()
        }
        job.join()
    }
    Thread.sleep(100)
    println("test completed")
}

Then I try to add my custom CoroutineExceptionHandler into scope's context:

@Test
fun exceptionHandler() {
    runBlocking {
        val exceptionHandler = CoroutineExceptionHandler { _, throwable -> {
            println("Caught exception")
        }}
        val scope = CoroutineScope(Dispatchers.Default + exceptionHandler)
        val job = scope.launch() {
            delay(100)
            println("inside coroutine")
        }
        scope.launch {
            delay(50)
            throw Exception()
        }
        job.join()
    }
    Thread.sleep(100)
    println("test completed")
}

This makes the previous message about the exception go away (which probably means that my custom handler replaced the default one), but handleException() of my custom handler isn't invoked and I don't see "Caught exception" in the output (only "Test completed").

I thought maybe it's something related to unit tests, so I tried this same code in Android app. The result is the same: upon exception the app doesn't crash (which means that the default handler was replaced), but my custom handler's handleException() function isn't called.

This feels wrong. Is it the intended behavior or a bug?

Upvotes: 0

Views: 1184

Answers (1)

Vasiliy
Vasiliy

Reputation: 16228

Crap, I've just wasted an entire hour due to extra pair of curly braces.

I wrote this:

    val exceptionHandler = CoroutineExceptionHandler { _, throwable -> {
        println("Caught exception")
    }}

But the correct way of using that is this:

    val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        println("Caught exception")
    }

Then it works.

Upvotes: 5

Related Questions