Most coroutine bugs I see in code review are not syntax mistakes. They are routing mistakes: an exception that went somewhere nobody was listening, a failure that cancelled work it had no business cancelling, or a blocking call that quietly froze the UI. All of them trace back to picking the wrong builder for the job.
Kotlin gives you six everyday tools for starting concurrent work: launch , async , runBlocking , coroutineScope , supervisorScope , and withContext . Strictly speaking, only the first three are coroutine builders ; the last three are scoping and context functions. In practice you choose among all six at the same decision point, so this post treats them as one family.
Every choice comes down to three questions:
Do I need a result? (value back, or just a side effect)
How should failure travel?…