Skip to content
tezvyn:

Coroutine Exception Handling: launch vs. async

Source: kotlinlang.orgHardHow cards are made

Coroutine Exception Handling: launch vs. async

Coroutine builders handle exceptions differently. launch propagates them immediately, crashing if unhandled. async silently catches them, waiting for you to call await. Use a CoroutineExceptionHandler on root scopes for global logging.

Why it exists

Structured concurrency needs a clear way to handle errors. Without it, an error in one concurrent task could silently fail or bring down the whole system unpredictably. Coroutine exception handling provides clear, predictable rules for how errors propagate and are contained.

The mental model

Think of coroutine builders in two flavors. launch is 'eager' with exceptions: it propagates them immediately, treating them like uncaught thread exceptions. async is 'lazy': it catches its own exceptions and stores them in the Deferred result, waiting for you to call await inside a try/catch block. It's the difference between 'crash now' and 'handle later'.

How it works

When a launch coroutine fails, the exception travels up the job hierarchy. If it reaches the root of the coroutine scope and is unhandled, it will crash the application. In contrast, an exception inside an async block is caught and stored within its Deferred object. The program only becomes aware of the exception when await() is called, which will re-throw it. This allows the caller to handle it in a standard try/catch block.

For uncaught exceptions from launch, you can install a CoroutineExceptionHandler in the coroutine's context. This acts as a last-resort safety net, similar to Thread.uncaughtExceptionHandler. It's for logging or cleanup, not for recovering the failed coroutine, which is already complete when the handler is called.

When to use it

Use launch for fire-and-forget operations where an exception should be a critical, visible failure that needs to be logged globally. Use async when you are computing a value that might fail, and the calling code needs to decide how to handle that failure, for example by providing a default value or retrying.

When not to use it

Do not attach a CoroutineExceptionHandler to an async block; it will have no effect because async always catches its own exceptions. Also, do not install an exception handler on a child coroutine expecting it to catch its own exceptions; children always delegate exception handling to their parent.

One canonical example

A root launch coroutine throwing an IndexOutOfBoundsException will immediately propagate the exception, which is then handled by the thread's uncaught exception handler. A root async coroutine throwing an ArithmeticException will do nothing until deferred.await() is called within a try/catch block, at which point the exception is caught and handled by the caller.

Interview question

An exception occurs inside an `async` block. The `Deferred` result is stored, but `await()` is never called on it. What happens to the exception?

  • a.It is handled by the nearest `CoroutineExceptionHandler` in the context.
  • b.It is caught and held within the `Deferred` object, and program execution continues.Correct
  • c.It propagates up the coroutine hierarchy, potentially crashing the application.
  • d.It is silently ignored and permanently lost, as if it never happened.
Why?

`async` catches its own exceptions and stores them in the `Deferred` result. The exception is only re-thrown when `await()` is called. Option C describes the behavior of `launch`, a common point of confusion.

Just read this? Test yourself on what you have been reading.

Read the original → kotlinlang.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on kotlin — each one lists the topics its interview covers.

See open roles