Improved runCatching
I have many issues with runCatching from Kotlin stdlib. Not that it isn't useful, there is certainly a need for it, the issue is that it is poorly implemented. This is its current implementation:
inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: Throwable) {
Result.failure(e)
}
}
Now here are the issues I have with it:
- It is catching all exceptions, including
OutOfMemoryError or other unrecoverable ones. It is a known anit-pattern. - It is catching exceptions used to signal cancellation.
- It lacks a contract that would allow the compiler to better reason about its usages.
First, we should catch Exception instead of Throwable. Throwable covers Error and Exception. Error shouldn't be caught as it is used to signal unrecoverable errors.
inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: Exception) { // <- Exception instead of Throwable
Result.failure(e)
}
}
Second, we deal with exceptions used to signal cancellations. In Kotlin Coroutines it is CancellationException, in JVM stdlib it is InterruptedException. They are both a subtype of Exception, so we must catch and throw them above Exception. Typically, KMP projects and projects that use Kotlin coroutines only support CancellationException:
inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Result.failure(e)
}
}
Teams that don't use Kotlin coroutines often only support InterruptedException:
inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: InterruptedException) {
throw e
} catch (e: Exception) {
Result.failure(e)
}
}
For our example, we will support both, though I rarely see that in practice.
Finally, we can add a contract that specifies that the block is called exactly once. It will add some smartness to this function:
Now let's discuss the name. I can see some teams naming it just runCatching, and remembering to import it. I prefer giving it a different name for clarity. My suggestion is runCatchingCancellable. Here is the complete function:
@OptIn(ExperimentalContracts::class)
inline fun <T> runCatchingCancellable(block: () -> T): Result<T> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return try {
Result.success(block())
} catch (e: CancellationException) {
throw e
} catch (e: InterruptedException) {
throw e
} catch (e: Exception) {
Result.failure(e)
}
}
If you want to understand cancellation and dive deep into Kotlin Coroutines, join the Coroutines Mastery cohort course. We will have a lot of fun there!

Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.