{"id":689112,"date":"2026-03-19T11:00:58","date_gmt":"2026-03-19T10:00:58","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=689112"},"modified":"2026-03-19T11:01:05","modified_gmt":"2026-03-19T10:01:05","slug":"intellij-idea-s-new-kotlin-coroutine-inspections-explained","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/pt-br\/idea\/2026\/03\/intellij-idea-s-new-kotlin-coroutine-inspections-explained","title":{"rendered":"IntelliJ IDEA&#8217;s New Kotlin Coroutine Inspections, Explained"},"content":{"rendered":"\n<p><em>This article was written by an external contributor.<\/em><\/p>\n\n\n    <div class=\"about-author \">\n        <div class=\"about-author__box\">\n            <div class=\"row\">\n                                                            <div class=\"about-author__box-img\">\n                            <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/10\/image-96.png\" alt=\"\" loading=\"lazy\">\n                        <\/div>\n                                        <div class=\"about-author__box-text\">\n                                                    <h4>Marcin Moska\u0142a<\/h4>\n                                                <p>Marcin is a highly experienced developer and Kotlin instructor, founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training. He is also a Google Developers Expert and a well-known contributor to the Kotlin community. Marcin is the author of several widely recognized books, including <em data-start=\"450\" data-end=\"468\">Effective Kotlin<\/em>, <em data-start=\"470\" data-end=\"489\" data-is-only-node=\"\">Kotlin Coroutines<\/em>, <em data-start=\"491\" data-end=\"510\">Functional Kotlin<\/em>, <em data-start=\"512\" data-end=\"529\">Advanced Kotlin<\/em>, <em data-start=\"531\" data-end=\"550\">Kotlin Essentials<\/em>, and <em data-start=\"556\" data-end=\"589\">Android Development with Kotlin<\/em>.<\/p>\n<p><a href=\"https:\/\/kt.academy\/\" target=\"_blank\" rel=\"noopener\">Website<\/a><\/p>\n                    <\/div>\n                            <\/div>\n        <\/div>\n    <\/div>\n\n\n\n<p>Every technology has its misuses, and different ecosystems use different approaches to prevent them. In the Kotlin ecosystem, I believe the philosophy has always been to make APIs so good that correct usage is simple and intuitive, while misuse is harder and more complicated. This differs from JavaScript, which has plenty of legacy practices (like using == instead of ===, or <code>var<\/code> instead of <code>let\/const<\/code>) and relies more on warnings. However, not everything can be enforced by good design, and Kotlin also uses warnings to guide developers in writing better code.&nbsp;<\/p>\n\n\n\n<p>Today, IntelliJ IDEA introduces a set of new inspections for the Kotlin coroutines library. I\u2019ve seen these issues in many codebases and addressed them through my books, articles, and workshops. These patterns often show up, so let\u2019s walk through why they are problematic and how to handle them correctly.&nbsp;<\/p>\n\n\n\n<p>Note: These inspections are also available in Android Studio. You can check how IntelliJ IDEA versions map to Android Studio versions <a href=\"https:\/\/plugins.jetbrains.com\/docs\/intellij\/android-studio-releases-list.html#2025\" target=\"_blank\" rel=\"noopener\">here<\/a>.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>awaitAll()<\/code>and <code>joinAll()<\/code><\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2025.2<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"2278\" height=\"1532\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image-34.png\" alt=\"\" class=\"wp-image-689987\"\/><\/figure>\n\n\n\n<p>If you use map <code>{ it.await() }<\/code>, IntelliJ IDEA will suggest <code>awaitAll()<\/code>. If you use <code>forEach { it.join() }<\/code>, it will suggest <code>joinAll()<\/code>. Why? These alternatives are cleaner, and <code>awaitAll()<\/code> is also more efficient and better represents waiting for multiple tasks, as it waits for all elements concurrently rather than one after another.&nbsp;<\/p>\n\n\n\n<p><code>awaitAll()<\/code> also behaves more efficiently in the presence of exceptions. Imagine awaiting 100 coroutines, and the fiftieth throws an exception. <code>awaitAll()<\/code> will immediately rethrow the exception, unlike map <code>{ it.await() }<\/code>, which would wait for the first 49 coroutines before throwing the exception. In most cases, this behavior cannot be observed because of other exception propagation mechanisms.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>currentCoroutineContext()<\/code> over <code>coroutineContext<\/code><\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2025.2<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1392\" height=\"888\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image_2.png\" alt=\"\" class=\"wp-image-689310\"\/><\/figure>\n\n\n\n<p>All suspending functions can access the context of the coroutine in which they are called. Traditionally, this was done via the <code>coroutineContext<\/code> property. The problem is that <code>CoroutineScope<\/code>, which is implicitly available in coroutine starters, such as launch, <code>coroutineScope<\/code>, and <code>runTest<\/code>, has a property with the same name. This can be confusing and lead to issues. Consider the following example:&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1900\" height=\"1051\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image12.png\" alt=\"\" class=\"wp-image-689321\"\/><\/figure>\n\n\n\n<p>This code tests the <code>mapAsync<\/code> function and checks whether it correctly propagates context from the caller to the transformation. It is incorrect. Within the transformation, we could read the caller context from the <code>coroutineContext<\/code>, but not in this situation. This lambda is defined inside <code>runTest<\/code>, and the <code>coroutineContext<\/code> property from <code>CoroutineScope<\/code> (provided by <code>runTest<\/code>) takes priority over the top-level <code>coroutineContext<\/code> property. This kind of mistake is quite common, which is why the <code>currentCoroutineContext()<\/code> function was introduced to read the context of the coroutine that runs a suspending function. You should use it instead of <code>coroutineContext<\/code>.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>runBlocking<\/code> inside a suspending function<\/h2>\n\n\n\n<p>Available since IDEA 2025.2<\/p>\n\n\n\n<p>Using <code>runBlocking<\/code> inside suspending functions is a serious issue. It blocks the calling thread, which defeats the purpose of coroutines.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1789\" height=\"315\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image10-2.png\" alt=\"\" class=\"wp-image-689332\"\/><\/figure>\n\n\n\n<p>So what can you use instead? That depends on what you want to achieve. In most cases, you don\u2019t need it. If you need to create a coroutine scope, use <code>coroutineScope { \u2026 }<\/code>. If you need to change context, use <code>withContext(ctx) { \u2026 }<\/code>.<br>Watch out for situations where a suspending function calls a regular function that uses runBlocking. Opt for making this function suspend to avoid making a blocking call.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1732\" height=\"1291\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image9-1.png\" alt=\"\" class=\"wp-image-689343\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Unused <code>Deferred<\/code><\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2025.3<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image-29.png\" alt=\"\" class=\"wp-image-689126\"\/><\/figure>\n\n\n\n<p>This inspection appears when you use async without ever using its result. In such cases, you should use launch instead. This is the key difference between launch and <code>async<\/code>: <code>async<\/code> returns a result and is expected to await this result, while <code>launch<\/code> produces no result.&nbsp;<\/p>\n\n\n\n<p>Because of this, exception handling differs. <code>async<\/code> doesn\u2019t call <code>CoroutineExceptionHandler<\/code> because it is expected to throw an exception from await and propagate it this way.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>Job<\/code> used as an argument in a coroutine starter<\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2025.3<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1312\" height=\"649\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image-33.png\" alt=\"\" class=\"wp-image-689227\"\/><\/figure>\n\n\n\n<p>I\u2019ve been looking forward to this inspection for years! Using <code>Job<\/code> as an argument to a coroutine starter causes issues, and it\u2019s something I\u2019ve seen in many projects. I covered this anti-pattern in my book and workshops, but it still appears quite often. This inspection should help clarify the correct approach. Let\u2019s look at why <code>Job<\/code> shouldn\u2019t be used as an argument for a coroutine.&nbsp;<\/p>\n\n\n\n<p>The key misunderstanding here is that <code>Job<\/code> cannot be overridden by an argument. If you use any other context, it will be used in the coroutine and its children, but not <code>Job<\/code>. Every coroutine creates its own job. A job contains a coroutine\u2019s state and relations \u2013 it cannot be shared or enforced from outside. The <code>Job<\/code> that is used as an argument isn\u2019t going to be a job of this coroutine. Instead, it overrides <code>Job<\/code> from the scope and becomes a parent. This breaks structured concurrency.<\/p>\n\n\n\n<p>For example: Using <code>withContext(SupervisorJob()) { \u2026 }<\/code> behaves very differently from <code>supervisorScope { \u2026 }<\/code>.&nbsp;<\/p>\n\n\n\n<p><code>supervisorScope<\/code> creates a child coroutine of the caller of this function, and it uses a supervisor job (it doesn\u2019t propagate its children\u2019s exceptions). On the other hand, <code>withContext(SupervisorJob())<\/code> creates a regular coroutine, which is a child of <code>SupervisorJob<\/code> and has no relation to the caller.&nbsp;<\/p>\n\n\n\n<p>Consider the code below. An exception in the first launch propagates to <code>withContext<\/code> (which uses regular <code>Job<\/code>), cancels the other child coroutines, and is then rethrown. <code>SupervisorJob()<\/code> has no effect. In some cases, it can even be harmful, as it breaks structured concurrency. If the caller of <code>withContext(SupervisorJob())<\/code> is cancelled, that cancellation won\u2019t propagate, which will result in a memory leak.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import kotlinx.coroutines.*\n\nval handler = CoroutineExceptionHandler { _, e ->\n\u00a0\u00a0\u00a0println(\"Exception:\u00a0 ${e.message}\")\n}\n\nfun main(): Unit = runBlocking(handler) {\n\u00a0\u00a0\u00a0\/\/ DON'T DO THAT!\n\u00a0\u00a0\u00a0withContext(SupervisorJob()) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0launch {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0delay(1000)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0throw Error(\"Some error\")\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0launch {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0delay(2000)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0println(\"AAA\")\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0}\n\u00a0\u00a0println(\"Done\")\n}\n\/\/ (1 sec)\n\/\/ Exception in thread \"main\"...<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"673\" height=\"516\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image-30.png\" alt=\"\" class=\"wp-image-689146\"\/><\/figure>\n\n\n\n<p>Using <code>supervisorScope<\/code> would prevent this problem:&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import kotlinx.coroutines.*\n\nval handler = CoroutineExceptionHandler { _, e ->\n\u00a0\u00a0\u00a0println(\"Exception:\u00a0 ${e.message}\")\n}\n\nfun main(): Unit = runBlocking(handler) {\n\u00a0\u00a0supervisorScope {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0launch {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0delay(1000)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0throw Error(\"Some error\")\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0launch {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0delay(2000)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0println(\"AAA\")\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0}\n\u00a0\u00a0println(\"Done\")\n}\n\/\/ (1 sec)\n\/\/ Exception:\u00a0 Some error\n\/\/ (1 sec)\n\/\/ AAA\n\/\/ Done<\/pre>\n\n\n\n<p>A <code>Job<\/code> used as an argument breaks the relationship with the caller. In the case below, <code>updateToken<\/code> won\u2019t be related to the caller of <code>getToken<\/code>:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">suspend fun getToken(): Token = coroutineScope {\n\u00a0\u00a0\u00a0val token = tokenRepository.fetchToken()\n\u00a0\u00a0\u00a0launch(Job()) { \/\/ Poor practice\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tokenRepository.updateToken(token)\n\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0token\n}<\/pre>\n\n\n\n<p>This is generally discouraged, as it breaks structured concurrency. The standard approach would be to sequentially call <code>updateToken<\/code>:&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">suspend fun getToken(): Token {\n\u00a0\u00a0\u00a0val token = tokenRepository.fetchToken()\n\u00a0\u00a0\u00a0tokenRepository.updateToken(token)\n\u00a0\u00a0\u00a0return token\n}<\/pre>\n\n\n\n<p>If we really want to detach <code>updateToken<\/code> from <code>getToken<\/code>, a better practice would be to start the launch on a different scope, like the backgroundScope we define in our application for background tasks. With this approach, the new coroutine is still attached to a scope, just a different one:&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">suspend fun getToken(): Token {\n\u00a0\u00a0\u00a0val token = tokenRepository.fetchToken()\n\u00a0\u00a0\u00a0backgroundScope.launch { \/\/ Acceptable\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tokenRepository.updateToken(token)\n\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0return token\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><code>suspendCancellableCoroutine<\/code> instead of <code>suspendCoroutine<\/code><\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2025.3<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image-32.png\" alt=\"\" class=\"wp-image-689233\"\/><\/figure>\n\n\n\n<p>To suspend a coroutine, use <code>suspendCancellableCoroutine<\/code>. Its predecessor, <code>suspendCoroutine<\/code>, does not support cancellation and should be avoided.<br><code>suspendCancellableCoroutine<\/code> is a low-level API rarely used in application code, but often used by libraries that support suspending calls.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Suspicious implicit <code>CoroutineScope<\/code> receiver<\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2025.3, but this inspection is disabled by default and must be enabled manually.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1999\" height=\"652\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image13.png\" alt=\"\" class=\"wp-image-689354\"\/><\/figure>\n\n\n\n<p>Implicit receivers within lambdas can be confusing. In the above example, <code>async<\/code> calls are executed on the scope created by <code>coroutineScope<\/code> because <code>collectLatest<\/code> doesn\u2019t provide its own scope. This can lead to memory leaks. When a new value reaches <code>collectLatest<\/code>, it should cancel processing of the previous one. In this example, it cannot cancel the <code>async<\/code> coroutines, as they are attached to <code>coroutineScope<\/code>, not to <code>collectLatest<\/code>. To avoid this, define <code>coroutineScope<\/code> inside <code>collectLatest<\/code>, not outside it. This inspection highlights such cases to prevent these issues.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image-31.png\" alt=\"\" class=\"wp-image-689175\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Simpler operations for flow processing<\/h2>\n\n\n\n<p>Available since IntelliJ IDEA 2026.1 (currently in EAP)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"1677\" height=\"889\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2026\/03\/image_1-1.png\" alt=\"\" class=\"wp-image-689366\"\/><\/figure>\n\n\n\n<p>You may already know these from collection or sequence processing:<br>If you use <code>filterNotNull<\/code> after map, you\u2019ll get the suggestion to use <code>mapNotNull<\/code>. If you use filter <code>{ it is T }<\/code>, the IDE will suggest using <code>filterNotNull&lt;T&gt;<\/code>.<br>These suggestions are now also available for flows!&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>IntelliJ IDEA continues to help you write better code \u2013 not only by advancing its AI tools and agents, but also by improving the core development experience. There are still many inspections I would love to see in the IDE, but the current set already brings significant value.<\/p>\n","protected":false},"author":1138,"featured_media":689378,"comment_status":"closed","ping_status":"closed","template":"","categories":[4113],"tags":[6850,756,21],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea\/689112"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/users\/1138"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/comments?post=689112"}],"version-history":[{"count":10,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea\/689112\/revisions"}],"predecessor-version":[{"id":690091,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/idea\/689112\/revisions\/690091"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/media\/689378"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/media?parent=689112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/categories?post=689112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/tags?post=689112"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/pt-br\/wp-json\/wp\/v2\/cross-post-tag?post=689112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}