Pooya
Pooya

Reputation: 89

How can I catch an exception in Kotlin coroutine when I am awaiting it in another function?

Sorry for the vague title, couldn't come up with something better.

So I read this article and wanted to do the same. problem is that I can't do try { promise... } catch (e) { } cause the error gets swallowed. I can catch the error where I await it, but I don't want that.

and my code looks like this:

typealias Promise<T> = Deferred<T>

fun <T, R> Promise<T>.then(handler: (T) -> R): Promise<R> = GlobalScope.async(Dispatchers.Main) {
    // using try/catch here works but I don't want it here.
    val result = [email protected]()
    handler.invoke(result)
}

object PromiseUtil {
    fun <T> promisify(block: suspend CoroutineScope.() -> T): Promise<T> = GlobalScope.async { block.invoke(this) }
}

// somewhere in my UI testing it.
try {
    PromiseUtil.promisify { throw Exception("some exp") }
        .then { Log.d("SOME_TAG", "Unreachable code.") }
} catch (e: Exception) {
    Log.d("ERROR_TAG", "It should catch the error here but it doesn't.")
}

And I read this and this one too, but I want to somehow catch errors in the UI code, and don't want to use runBlocking { ... }.

Thanks.

Upvotes: 1

Views: 2580

Answers (1)

veritas1
veritas1

Reputation: 9170

The exception is never caught because it's never propagated by the async call. That happens when await() is called.

See coroutine exception handling.

Your code should be:

// somewhere in my UI testing it.
try {
    PromiseUtil.promisify { throw Exception("some exp") }
        .then { Log.d("SOME_TAG", "Unreachable code.") }.await() // <--- added await() call
} catch (e: Exception) {
    Log.d("ERROR_TAG", "It should catch the error here but it doesn't.")
}

But this won't compile as await() is a suspending function. Therefore, it should be more like:

// somewhere in my UI testing it.
GlobalScope.launch(CoroutineExceptionHandler { coroutineContext, throwable ->
            Log.d("ERROR_TAG", "It will catch error here")
            throwable.printStackTrace()
        }) {
   PromiseUtil.promisify { throw Exception("some exp") }
        .then { Log.d("SOME_TAG", "Unreachable code.") }.await()
}

Upvotes: 5

Related Questions