Compare suspendCoroutine and suspendCancellableCoroutine. When is each appropriate?
answer
- suspendCoroutine = stdlib, not cancellable
- suspendCancellableCoroutine = kotlinx, cancellable + cleanup
- Default to the cancellable one
- Non-cancellable breaks withTimeout/structured concurrency
- Continuation vs CancellableContinuation
basics
~10 sBoth 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 ssuspendCoroutine 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
Knows both bridge callbacks and that one is cancellable.
Picks suspendCancellableCoroutine by default and explains the cleanup difference.
Explains the structured-concurrency/withTimeout consequences of choosing wrongly.
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