async/await Exception Propagation
Understand how exceptions from async propagate and when to use try-await.
async Stores Exceptions
Unlike launch, async stores the exception in the returned Deferred. It is only rethrown when you call await().
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred = async {
throw RuntimeException("async error")
}
try {
deferred.await() // exception rethrown here
} catch (e: RuntimeException) {
println("Caught: ${e.message}")
}
}Exception Without await()
If you never call await(), the exception is silently discarded with a regular Job parent. Prefer supervisorScope + always await.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Exception stored in deferred, never retrieved:
val d = async { throw RuntimeException("lost exception") }
delay(100) // d has failed — exception never surfaced
println("d.isCancelled: ${d.isCancelled}")
}All lessons in this course
- SupervisorJob vs Job: Failure Isolation
- CoroutineExceptionHandler: Global Uncaught Handler
- async/await Exception Propagation
- Designing Resilient Coroutine Architectures