Ambiguous coroutineContext due to CoroutineScope receiver of suspend function

I’m using the kotlinx-coroutines-debug module to debug a coroutine that suspends forever.

suspend fun <T> CoroutineScope.debugWithTimeout(
    timeout: Duration,
    block: suspend () -> T
) {
    DebugProbes.install()
    val deferred = async { block() }
    delay(timeout)
    DebugProbes.dumpCoroutines()
    println("\nDumping only deferred")
    DebugProbes.printJob(deferred)
    DebugProbes.uninstall()
}

I call it like so: debugWithTimeout(timeout = 3.toDuration(DurationUnit.SECONDS)) { methodThatHangs() }

However, the async invocation generates a warning

Ambiguous coroutineContext due to CoroutineScope receiver of suspend function

My understanding is the ambiguity is because async has access to two CoroutineContexts, one from scope this (CoroutineScope.coroutineContext), and another from kotlinx.coroutines.currentCoroutineContext(). However, wrapping the async call with coroutineScope, or useContext(this.coroutineContext) or useContext(currentCoroutineContext()) all block, and never execute the debug dumps. The only way it works is by ignoring the warning.

Can anyone please explain this behavior?

1 Like

Either start a coroutine with a CoroutineScope OR suspend within an existing coroutine. Avoid doing both, it’s confusing, even without the warning.

For more context: Coroutine Context and Scope
Easy way to ditch the warning is to launch the whole block instead of suspending.

fun <T> CoroutineScope.debugWithTimeout(
    timeout: Duration,
    block: suspend () -> T
) = launch {
    DebugProbes.install()
    val deferred = async { block() }
    delay(timeout)
    DebugProbes.dumpCoroutines()
    println("\nDumping only deferred")
    DebugProbes.printJob(deferred)
    DebugProbes.uninstall()
}
2 Likes

Thank you.

For those who didn’t notice the main difference: there is no suspend in the signature of the solution because launch coroutine builder doesn’t suspend execution.

For those who interested in further details: read the Explicit concurrency article that covers concurrent and sequential functions conventions in Kotlin coroutines.