codeInheaven
codeInheaven

Reputation: 3

Why exception thrown from child scope (launch) is not caught by parent catch block in Kotlin coroutine?

val parentScope = CoroutineScope(Dispatchers.Main)

parentScope.launch {
    try{
        launch{ // child scope
              //code ....
              throw CustomError("error", null)  
        }
    } catch(cause: CustomError){
        // It did not get executed
    }
    
}

In the above code snippet the app got crash. The exception thrown from it is not caught into the parentScope catch block.

But if we replace the above childScope with

supervisorScope or 
coroutineScope or
withContext or 
runBlocking

it catught the exception.

parentScope.launch {
    try{
          supervisorScope { 
             //code
             throw CustomError("error", null)   
          }
    } catch(cause: CustomError){
        // It get execute when withContext/supervisorScope
    }
}

Why exception thrown from child scope(launch) is not caught by parent catch block?

Exception:

FATAL EXCEPTION: DefaultDispatcher-worker-1
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) 

Upvotes: 0

Views: 465

Answers (1)

broot
broot

Reputation: 28462

Disclaimer: this question has been edited which greatly affected the answer. Original answer is below.

launch() is used to run the code asynchronously, in a separate coroutine or in the background. CustomError is not really thrown from within try...catch. Code which invokes launch() doesn't even wait for it to start executing - it only schedules the code to be executed and then immediately progress further.

This is similar to starting a new thread. If the thread throws, you can't catch this in the code that created or started the thread. Code that started the thread and the code inside the thread are running in two separate execution contexts.

All other functions you mentioned (coroutineScope(), runBlocking(), etc.) run synchronously - they wait for the block of code to be executed, they wait for its result. Inner block of code runs inside the same execution context as the outer one. For this reason exceptions could be propagated as usual.

Original answer:

In your first example there is really no parent-child relationship. Both parentScope and childScope are created separately and they run independently of each other. Simply because you put one code block inside another doesn't mean they are in any way related.

withContext() is different, it uses the current scope (parentScope) to execute the code.

In other words: whenever you use someScope.launch() this is like explicitly asking to switch to entirely different execution context.

Upvotes: 0

Related Questions