skip to content

Compare suspendCoroutine and suspendCancellableCoroutine. When is each appropriate?

level: middleimportance: should knowfreq 45%

answer

  1. suspendCoroutine = stdlib, not cancellable
  2. suspendCancellableCoroutine = kotlinx, cancellable + cleanup
  3. Default to the cancellable one
  4. Non-cancellable breaks withTimeout/structured concurrency
  5. Continuation vs CancellableContinuation

basics

~10 s

Both turn a callback into a suspend function. suspendCoroutine cannot react to cancellation; suspendCancellableCoroutine can cancel the underlying work and clean up. Prefer the cancellable one for almost everything.

solid answer

~40 s

suspendCoroutine lives in the Kotlin standard library (kotlin.coroutines) and gives a plain Continuation: you call resume / resumeWithException, but the coroutine cannot be cancelled while suspended in it and there is no cleanup hook. suspendCancellableCoroutine lives in kotlinx.coroutines and gives a CancellableContinuation: cancellation of the parent immediately resumes it with CancellationException, and invokeOnCancellation lets you abort the underlying operation. Use suspendCancellableCoroutine by default — it preserves structured concurrency, supports timeouts (withTimeout), and avoids leaking work after cancellation. Use suspendCoroutine only when the operation is truly non-cancellable and short, or when you have no kotlinx dependency. Choosing suspendCoroutine for a long network call breaks cooperative cancellation: a cancelled scope will wait for the call to finish instead of aborting it.

go deeper

for a junior

Knows both bridge callbacks and that one is cancellable.

for a middle

Picks suspendCancellableCoroutine by default and explains the cleanup difference.

for a senior

Explains the structured-concurrency/withTimeout consequences of choosing wrongly.

for a principal

Weighs dependency boundaries, library API design, and cancellation guarantees when exposing bridges.

## Two builders, one purpose Both are `suspend` builders that bridge callback/future APIs to suspend functions by handing you a continuation to resume later. | | `suspendCoroutine` | `suspendCancellableCoroutine` | |---|---|---| | Package | `kotlin.coroutines` (stdlib) | `kotlinx.coroutines` | | Continuation type | `Continuation<T>` | `CancellableContinuation<T>` | | Reacts to cancellation while suspended | **No** | **Yes** | | Cleanup hook | none | `invokeOnCancellation { }` | | `withTimeout` can interrupt it | No | Yes | ## Why cancellation matters Structured concurrency and `withTimeout` rely on suspension points being **cancellable**. If you suspend in `suspendCoroutine` and the parent scope is cancelled, the coroutine **cannot resume until the callback fires** — the cancellation is deferred, the underlying request keeps running, and a `withTimeout` will not actually interrupt the wait. With `suspendCancellableCoroutine`, cancellation resumes the continuation with `CancellationException` right away, and `invokeOnCancellation` aborts the underlying work. ## Code contrast ```kotlin // Not cancellable: a cancelled scope still waits for onResult suspend fun a(cb: CbApi) = suspendCoroutine<Int> { c -> cb.start { c.resume(it) } } // Cancellable: parent cancellation aborts and cleans up suspend fun b(cb: CbApi) = suspendCancellableCoroutine<Int> { c -> val h = cb.start { c.resume(it) } c.invokeOnCancellation { cb.stop(h) } } ``` ## When suspendCoroutine is fine - The operation is **instant/non-cancellable** (e.g. a synchronous compute wrapped in a callback). - You are in a **stdlib-only** context with no kotlinx.coroutines dependency. In practically all I/O bridges, choose `suspendCancellableCoroutine`.

  • Why does suspendCoroutine break withTimeout?
    Its suspension point is not cancellation-aware, so the timeout cannot resume the coroutine until the callback fires; the wait is not actually interrupted.
  • Where does each type live?
    suspendCoroutine and Continuation are in kotlin.coroutines (stdlib); suspendCancellableCoroutine and CancellableContinuation are in kotlinx.coroutines.

saying these in an interview costs you the question

  • Says they are interchangeable in all cases
  • Uses suspendCoroutine for long network calls
  • Thinks suspendCoroutine supports invokeOnCancellation
  • Believes withTimeout interrupts a suspendCoroutine wait
  • Cannot say which package each comes from

context