Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runBlocking rethrows exception which has been caugh inside it's block lambda #2404

Closed
pchmielowski opened this issue Nov 23, 2020 · 2 comments

Comments

@pchmielowski
Copy link

pchmielowski commented Nov 23, 2020

Kotlin version: 1.4.10
Kotlin coroutines version: 1.4.1

Consider the following code:

fun main() {
    runBlocking {
        val numberAsync = async<Int> { throw Exception() }
        val number = try {
            numberAsync.await()
        } catch (e: Exception) {
            42
        }
        println(number)
    }
}

As Exception is caught by catch block, it is expected for the program to print just `42.
However running it gives the following result:

42
Exception in thread "main" java.lang.Exception
	at net.package.MainKt$main$1$numberAsync$1.invokeSuspend(main.kt:9)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at net.package.MainKt.main(main.kt:8)
	at net.package.MainKt.main(main.kt)

Which means runBlocking thrown this exception, even though it had been already caught.

I'm reporting this issue as a bug, because for me it seems to be one, however please let me know if this behaviour is an expected one. If this is the case, it would be worth considering to update the documentation of runBlocking function.

@fvasco
Copy link
Contributor

fvasco commented Nov 23, 2020

As Exception is caught by catch block, it is expected for the program to print just `42.

No, it is expected the coroutine scope cancellation, by design.

https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html#structured-concurrency-with-async

You can catch and handle the error, but the scope has been cancelled.

Here a simpler reproducer

fun main() {
    runBlocking {
        async<Int> { throw Exception() }
    }
}

Do you agree?

@elizarov
Copy link
Contributor

Concurrent operations like async always work in a scope which gets cancelled on any error. To catch errors arising from async operations use try { ... } catch around coroutineScope:

val number = try {
    coroutineScope { // limits the scope of concurrency 
        val numberAsync = async<Int> { throw Exception() }
        numberAsync.await()
    }
} catch (e: Exception) {
     42
}
println(number)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants