Description
Describe the bug
In Kotlin/JS, when resuming the main coroutine exceptionally, the exception is thrown is the resuming coroutine (even if it's in a different scope) and it's not propagated in the main coroutine scope.
This happens with Kotlin/JS. Coroutines version 1.7.3. Kotlin version 1.9.21.
Provide a Reproducer
Create a basic Kotlin/JS project with the following main file:
import kotlinx.coroutines.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resumeWithException
val mainContinuation = CompletableDeferred<Continuation<Unit>>()
val scope = CoroutineScope(EmptyCoroutineContext)
suspend fun main() {
// Wait for the main coroutine to suspend and resume it exceptionally
scope.launch {
val continuation = mainContinuation.await()
val exception = Exception("Test exception")
try {
continuation.resumeWithException(exception)
} catch (unexpected: Throwable) {
// This should get printed
println("Unexpected exception: $unexpected")
}
}
// Suspend the main coroutine
suspendCancellableCoroutine {
mainContinuation.complete(it)
}
}
What I expect: the main coroutine is resumed exceptionally and the exception ends up in the global uncaught handler, the resuming coroutine is not affected, as it is in a different scope.
What happens instead: the main coroutine is resumed exceptionally, but then the exception is propagated to the resumer coroutine and caught in the catch block, printing Unexpected exception: Exception: Test exception
. The global uncaught exception handlers is not invoked, as the exception doesn't appear in the console as it normally does otherwise.
More details:
Catching the exception in the main coroutine prevents it from being propagated to the resumer.
Wrapping the main suspending point in
// Suspend the main coroutine
try {
suspendCancellableCoroutine {
mainContinuation.complete(it)
}
} finally {
delay(1)
}
"fixes it" as the exception is no more propagated to the resumer and ends up in the uncaught handler.
If I understand coroutines, this is not the expected behavior, and it doesn't happen on JVM for example 🤔