kotlinx.coroutines.flow.internal.ChildCancelledException: Child of the scoped flow was cancelled
See original GitHub issueHi, in my app I randomly get a ChildCancellationException
. It comes from the flatMapLatest
operator (previously named switchMap
). I tested it on the JVM with versions 1.3.0-M2, 1.3.0-RC, 1.3.0-RC2. I was able to reproduce it in a test:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
class MyTest {
@Test
fun test(): Unit = runBlocking {
val context = Dispatchers.Default
val deferred = GlobalScope.async(context) {
launch(context) {
observeFlow().collect {}
}
while (true) {
channel.send(channel.value)
}
}
deferred.await()
}
val channel = ConflatedBroadcastChannel("")
val flow = channel.asFlow()
fun observeFlow() = flow.flatMapLatest {
val flows = List(2) {
flow {
while (true) {
emit("")
}
}
}
combine(flows) { it.asList() }
}
}
Exception in thread "DefaultDispatcher-worker-5 @coroutine#716" kotlinx.coroutines.flow.internal.ChildCancelledException: Child of the scoped flow was cancelled
(Coroutine boundary)
at kotlinx.coroutines.channels.AbstractChannel.registerSelectReceiveOrNull(AbstractChannel.kt:753)
at kotlinx.coroutines.channels.AbstractChannel.access$registerSelectReceiveOrNull(AbstractChannel.kt:484)
at kotlinx.coroutines.channels.AbstractChannel$onReceiveOrNull$1.registerSelectClause1(AbstractChannel.kt:732)
at kotlinx.coroutines.selects.SelectBuilderImpl.invoke(Select.kt:415)
at kotlinx.coroutines.flow.internal.CombineKt$combineInternal$2.invokeSuspend(Combine.kt:151)
Caused by: kotlinx.coroutines.flow.internal.ChildCancelledException: Child of the scoped flow was cancelled
at kotlinx.coroutines.flow.internal.ChannelFlowTransformLatest$flowCollect$3$invokeSuspend$$inlined$collect$1.emit(Collect.kt:137)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAll(Channels.kt:56)
at kotlinx.coroutines.flow.FlowKt.emitAll(Unknown Source)
at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAll$1.invokeSuspend(Channels.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
Of course this test is not my real code, but this appears to reproduce the exception (almost) every time it is run. You may need to run the test again if you do not get the exception. It should happen within a few seconds of running the test.
Is this expected behaviour and/or is there anything I can do to fix this?
There was a discussion about this on Slack with @qwwdfsad: https://kotlinlang.slack.com/archives/C1CFAFJSK/p1563388954310700
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (4 by maintainers)
Top Results From Across the Web
How to spot where "Job was cancelled" exception comes from ...
The issue was coming from Kotlin Flow trying to emit after ... become children of the Job in scope (MainScope in your Scoped...
Read more >Cancellation in coroutines - Medium
If the child was cancelled due to CancellationException , then no other action is required for the parent. ⚠️Once you cancel a scope,...
Read more >Hello some of my users are getting this crash in my app Fata
Fatal Exception: kotlinx.coroutines.flow.internal.ChildCancelledException Child of the scoped flow was cancelled. For some reason this crash does not have a ...
Read more >Kotlin Coroutines by Tutorials, Chapter 9: Manage Cancellation
They are typically thrown by cancellable suspending functions if the Job of the coroutine is canceled while it is suspending. It indicates normal...
Read more >Job and children awaiting in Kotlin Coroutines - Kt. Academy
children inherit context from their parent; · a parent suspends until all the children are finished; · when the parent is cancelled, its...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I still see this on 1.3.2. I’m not sure if I’m doing something wrong, but the use case is very similar to the one described.
The issue happens when the callback inside a
channelFlow
, inside aflatMapLatest
, tries tooffer
the channel a value after thechannelFlow
is already cancelled.Code:
Stacktrace shows the line that caused the crash was:
offer(it)
Inside the Firebase listener, inside the
channelFlow
.Reading #1454, It seems perhaps it is as expected. Using
send
inside alaunch
coroutine on the callback seems to fix it. This is quite unexpected to me, though, and it should be mentioned clearly on thechannelFlow
documentation, which uses an example withoffer
.Apparently, it is a bug in the underlying implementation mechanism of
combine
Will be fixed in 1.3.0, thanks for the repro