Catching every exception around a coroutine can accidentally turn cancellation into an ordinary application failure. A screen closes, the job is cancelled, and a broad catch block decides to display an error or try again. The code is being helpful about work that was supposed to stop.
Kotlin’s cancellation guide explains that cancellation is cooperative and uses CancellationException. If you catch that exception while handling other failures, rethrow it so cancellation can continue through the coroutine machinery. The surrounding scope and the work inside it both need to participate.
For me, a useful check is to cancel the operation at a realistic point and observe what follows. Does the child work finish, are resources released, and does the closed screen stay closed? Testing only the successful return value leaves out the behaviour that matters when someone navigates away halfway through.
This does not need a complicated exception hierarchy. It needs error handling that distinguishes an operation failing from its owner no longer wanting it. Make that distinction visible, keep cleanup reliable, and resist turning every interrupted job into a fresh attempt. Sometimes the correct outcome is simply that the work stops.

