Kotlinx.coroutines: CompletedContinuation cannot be cast to DispatchedContinuation

Created on 31 Mar 2020  路  13Comments  路  Source: Kotlin/kotlinx.coroutines

Platform: iOS, org.jetbrains.kotlinx:kotlinx-coroutines-core-iosarm64
Version: 1.3.5-native-mt

Example:

class IssueReproduce: CoroutineScope {
    private val dispatcher = DispatchersProvider.dispatcherUi
    private val job = SuperviserJob()
    private val someApi = SomeApi()

    override val coroutineContext: CoroutineContext
        get() = dispatcher + job

    fun performApiCall(callback: (SomeDataClass) -> Unit) {
        launch(coroutineContext) {
            val response = someApi.someMethod()

            callback(response)
        }
    }
}

/* ... */

actual object DispatchersProvider {
    actual val dispatcherUi: CoroutineDispatcher = IosMainDispatcher
}

private object IosMainDispatcher : CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        dispatch_async(dispatch_get_main_queue(), block::run)
    }
}

/* ... */

class SomeApi {
    private val client: HttpClient = /* ... */

    suspend fun someMethod(): SomeDataClass {
        return client.get { /* ... */ }
    }
}

If someApi.someMethod() is successful, all is ok.
But when (performApiCall called from iOS, and) someApi.someMethod() throws some exception, then below crash happens:

Uncaught Kotlin exception: kotlinx.coroutines.CoroutinesInternalError: Fatal exception in coroutines machinery for DispatchedContinuation[IosMainDispatcher@7c947c98, Continuation @ $getStories$lambda-0COROUTINE$6]. Please read KDoc to 'handleFatalException' method and report this incident to maintainers
        at 0   ExampleAppCommon                    0x00000001030047a8 kfun:kotlin.Error.<init>(kotlin.String?;kotlin.Throwable?)kotlin.Error + 116
        at 1   ExampleAppCommon                    0x0000000103134a20 kfun:kotlinx.coroutines.CoroutinesInternalError.<init>(kotlin.String;kotlin.Throwable)kotlinx.coroutines.CoroutinesInternalError + 116
        at 2   ExampleAppCommon                    0x0000000103170408 kfun:kotlinx.coroutines.DispatchedTask.handleFatalException$kotlinx-coroutines-core(kotlin.Throwable?;kotlin.Throwable?) + 708
        at 3   ExampleAppCommon                    0x00000001031700e0 kfun:kotlinx.coroutines.DispatchedTask.run() + 3024
        at 4   ExampleAppCommon                    0x00000001033654d8 kfun:com.example.presentation.IosMainDispatcher.$run$FUNCTION_REFERENCE$21.invoke#internal + 116
        at 5   ExampleAppCommon                    0x0000000103365538 kfun:com.example.presentation.IosMainDispatcher.$run$FUNCTION_REFERENCE$21.$<bridge-UNN>invoke()#internal + 64
        at 6   ExampleAppCommon                    0x000000010336574c _4e6967687453746f7279436f6d6d6f6e_knbridge9 + 188
        at 7   libdispatch.dylib                   0x0000000103bedd10 _dispatch_call_block_and_release + 32
        at 8   libdispatch.dylib                   0x0000000103bef18c _dispatch_client_callout + 20
        at 9   libdispatch.dylib                   0x0000000103bfdd14 _dispatch_main_queue_callback_4CF + 996
        at 10  CoreFoundation                      0x00000001b483741c 9624AAFD-5437-3772-A507-0F357875808D + 709660
        at 11  CoreFoundation                      0x00000001b4832034 9624AAFD-5437-3772-A507-0F357875808D + 688180
        at 12  CoreFoundation                      0x00000001b4831660 CFRunLoopRunSpecific + 480
        at 13  GraphicsServices                    0x00000001bec42604 GSEventRunModal + 164
        at 14  UIKitCore                           0x00000001b8a0615c UIApplicationMain + 1944
        at 15  Example App                         0x00000001024f205c main + 80
        at 16  libdyld.dylib                       0x00000001b46ad1ec 95B366E7-F5BD-3308-9416-24B35999029B + 4588
Caused by: kotlin.ClassCastException: kotlin.coroutines.native.internal.CompletedContinuation cannot be cast to kotlinx.coroutines.DispatchedContinuation
        at 0   ExampleAppCommon                    0x000000010300b1bc kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 92
        at 1   ExampleAppCommon                    0x000000010300401c kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 88
        at 2   ExampleAppCommon                    0x0000000103003ae0 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 88
        at 3   ExampleAppCommon                    0x0000000103004a8c kfun:kotlin.ClassCastException.<init>(kotlin.String?)kotlin.ClassCastException + 88
        at 4   ExampleAppCommon                    0x000000010304f680 ThrowClassCastException + 636
        at 5   ExampleAppCommon                    0x000000010312b444 kfun:kotlinx.coroutines.CoroutineDispatcher.releaseInterceptedContinuation(kotlin.coroutines.Continuation<#STAR>) + 196
        at 6   ExampleAppCommon                    0x00000001030292b4 kfun:kotlin.coroutines.native.internal.ContinuationImpl.releaseIntercepted() + 696
        at 7   ExampleAppCommon                    0x0000000103029844 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1008
        at 8   ExampleAppCommon                    0x000000010316fdfc kfun:kotlinx.coroutines.DispatchedTask.run() + 2284
        at 9   ExampleAppCommon                    0x00000001033654d8 kfun:com.example.mobile.IosMainDispatcher.$run$FUNCTION_REFERENCE$21.invoke#internal + 116
        at 10  ExampleAppCommon                    0x0000000103365538 kfun:com.example.mobile.IosMainDispatcher.$run$FUNCTION_REFERENCE$21.$<bridge-UNN>invoke()#internal + 64
        at 11  ExampleAppCommon                    0x000000010336574c _4e6967687453746f7279436f6d6d6f6e_knbridge9 + 188
        at 12  libdispatch.dylib                   0x0000000103bedd10 _dispatch_call_block_and_release + 32
        at 13  libdispatch.dylib                   0x0000000103bef18c _dispatch_client_callout + 20
        at 14  libdispatch.dylib                   0x0000000103bfdd14 _dispatch_main_queue_callback_4CF + 996
        at 15  CoreFoundation                      0x00000001b483741c 9624AAFD-5437-3772-A507-0F357875808D + 709660
        at 16  CoreFoundation                      0x00000001b4832034 9624AAFD-5437-3772-A507-0F357875808D + 688180
        at 17  CoreFoundation                      0x00000001b4831660 CFRunLoopRunSpecific + 480
        at 18  GraphicsServices                    0x00000001bec42604 GSEventRunModal + 164
        at 19  UIKitCore                           0x00000001b8a0615c UIApplicationMain + 1944
        at 20  Example App                         0x00000001024f205c main + 80
        at 21  libdyld.dylib                       0x00000001b46ad1ec 95B366E7-F5BD-3308-9416-24B35999029B + 4588
(lldb) 

How to fix this: simply wrap someApi.someMethod() call with try-catch, or use the CoroutineExceptionHandler. Yea, the issue persists only when there are some uncaught exceptions, but I think I want to see the exception that was thrown, not this exception which not refers to my code :)

native question

Most helpful comment

@qwwdfsad Getting the same crash with ktor 1.4.1 and coroutines 1.3.9-native-mt-2. How can we fix it?

All 13 comments

On -native-mt version you cannot implement IosMainDispatcher this way. It is not supported at the moment. You should use Dispatchers.Main instead.

Does it help?

@elizarov Idk why I closed this :)
There is the same issue with Dispatchers.Main, and the key question was about the CompletedContinuation cannot be cast to DispatchedContinuation and how to get the original exception's stack trace on iOS :)

The only part is changed is DispatchedContinuation[IosMainDispatcher@7c947c98, it is changed to DispatchedContinuation[MainDispatcher.

Maybe, the stack trace is too long, and in the Xcode I can see only the last two elements, and the original exception is simply deeper? So, how to see it?
If I catch the error in catch(e: Throwable) { /* here */ }, I can only see the com.package.Exception: message, and not the stack trace.

Do you have a short reproducer in native-mt branch using a standard Dispatchers.Main?

@elizarov, using coroutines 1.3.5-native-mt, this code

        CoroutineScope(Dispatchers.Main).launch {
            val deferredResult = CoroutineScope(Dispatchers.Default).async {
                val response = HttpClient().get<String> {
                    url("https://www.google.com")
                }
                // process response and generate result
                val result = /* ... */ response
                result
            }
            println(deferredResult.await())
        }

produces the same kotlin.ClassCastException: kotlin.coroutines.native.internal.CompletedContinuation cannot be cast to kotlinx.coroutines.DispatchedContinuation when called from iOS main thread.

Isn't this code supposed to work, since both Dispatchers.Main and (a single background thread version of) Dispatchers.Default are available for iOS with 1.3.5-native-mt (as stated at https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md)?

Same thing happens with this code

        CoroutineScope(Dispatchers.Main).launch {
            val result = withContext(Dispatchers.Default) {
                val response = HttpClient().get<String> {
                    url("https://www.google.com")
                }
                // process response and generate result
                val result = /* ... */ response
                result
            }
            println(result)
        }

PS: I think https://github.com/ktorio/ktor/issues/1540 is a related issue

I am experiencing this issue as well. Unfortunately, I do not have a consistent way to reproduce it yet.

I am using Coroutines 1.3.5-native-mt. All of my iOS code uses Dispatchers.Main at the moment.

Xcode shows the following:

Uncaught Kotlin exception: kotlinx.coroutines.CoroutinesInternalError: Fatal exception in coroutines machinery for DispatchedContinuation[MainDispatcher, Continuation @ $awaitSuspendCOROUTINE$1222]. Please read KDoc to 'handleFatalException' method and report this incident to maintainers
        at 0   common                              0x0000000107354d94 kfun:kotlin.Error.<init>(kotlin.String?;kotlin.Throwable?)kotlin.Error + 116
        at 1   common                              0x000000010744e69c kfun:kotlinx.coroutines.CoroutinesInternalError.<init>(kotlin.String;kotlin.Throwable)kotlinx.coroutines.CoroutinesInternalError + 116
        at 2   common                              0x00000001074cbc6c kfun:kotlinx.coroutines.DispatchedTask.handleFatalException$kotlinx-coroutines-core(kotlin.Throwable?;kotlin.Throwable?) + 708
        at 3   common                              0x00000001074cb944 kfun:kotlinx.coroutines.DispatchedTask.run() + 3024
        at 4   common                              0x0000000107505d10 kfun:kotlinx.coroutines.DarwinMainDispatcher.dispatch$lambda-0#internal + 112
        at 5   common                              0x00000001075060d0 kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$543.invoke#internal + 64
        at 6   common                              0x0000000107506130 kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$543.$<bridge-UNN>invoke()#internal + 64
        at 7   common                              0x00000001075071bc _6b6f746c696e782d636f726f7574696e65732d636f7265_knbridge828 + 188
        at 8   libdispatch.dylib                   0x000000010a9bdd10 _dispatch_call_block_and_release + 32
        at 9   libdispatch.dylib                   0x000000010a9bf18c _dispatch_client_callout + 20
        at 10  libdispatch.dylib                   0x000000010a9cdd14 _dispatch_main_queue_callback_4CF + 996
        at 11  CoreFoundation                      0x000000018d38f6b0 AF42303F-57B6-3C11-8F18-8E80ABF7D886 + 710320
        at 12  CoreFoundation                      0x000000018d38a2c8 AF42303F-57B6-3C11-8F18-8E80ABF7D886 + 688840
        at 13  CoreFoundation                      0x000000018d3898f4 CFRunLoopRunSpecific + 480
        at 14  GraphicsServices                    0x00000001977a0604 GSEventRunModal + 164
        at 15  UIKitCore                           0x000000019155d358 UIApplicationMain + 1944
        at 16  HueEssentials-dev                   0x0000000104902414 main + 80
        at 17  libdyld.dylib                       0x000000018d2052dc 322C4E05-D0CF-33F5-B996-CE5C67DF59B6 + 4828
Caused by: kotlin.ClassCastException: kotlin.coroutines.native.internal.CompletedContinuation cannot be cast to kotlinx.coroutines.DispatchedContinuation
        at 0   common                              0x000000010735b4e0 kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 92
        at 1   common                              0x0000000107354608 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 88
        at 2   common                              0x0000000107354044 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 88
        at 3   common                              0x0000000107355078 kfun:kotlin.ClassCastException.<init>(kotlin.String?)kotlin.ClassCastException + 88
        at 4   common                              0x00000001073a394c ThrowClassCastException + 636
        at 5   common                              0x000000010744490c kfun:kotlinx.coroutines.CoroutineDispatcher.releaseInterceptedContinuation(kotlin.coroutines.Continuation<#STAR>) + 196
        at 6   common                              0x000000010737ae8c kfun:kotlin.coroutines.native.internal.ContinuationImpl.releaseIntercepted() + 696
        at 7   common                              0x000000010737b41c kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 1008
        at 8   common                              0x00000001074cb660 kfun:kotlinx.coroutines.DispatchedTask.run() + 2284
        at 9   common                              0x0000000107505d10 kfun:kotlinx.coroutines.DarwinMainDispatcher.dispatch$lambda-0#internal + 112
        at 10  common                              0x00000001075060d0 kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$543.invoke#internal + 64
        at 11  common                              0x0000000107506130 kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$543.$<bridge-UNN>invoke()#internal + 64
        at 12  common                              0x00000001075071bc _6b6f746c696e782d636f726f7574696e65732d636f7265_knbridge828 + 188
        at 13  libdispatch.dylib                   0x000000010a9bdd10 _dispatch_call_block_and_release + 32
        at 14  libdispatch.dylib                   0x000000010a9bf18c _dispatch_client_callout + 20
        at 15  libdispatch.dylib                   0x000000010a9cdd14 _dispatch_main_queue_callback_4CF + 996
        at 16  CoreFoundation                      0x000000018d38f6b0 AF42303F-57B6-3C11-8F18-8E80ABF7D886 + 710320
        at 17  CoreFoundation                      0x000000018d38a2c8 AF42303F-57B6-3C11-8F18-8E80ABF7D886 + 688840
        at 18  CoreFoundation                      0x000000018d3898f4 CFRunLoopRunSpecific + 480
        at 19  GraphicsServices                    0x00000001977a0604 GSEventRunModal + 164
        at 20  UIKitCore                           0x000000019155d358 UIApplicationMain + 1944
        at 21  HueEssentials-dev                   0x0000000104902414 main + 80
        at 22  libdyld.dylib                       0x000000018d2052dc 322C4E05-D0CF-33F5-B996-CE5C67DF59B6 + 4828

One time I got this stack trace below from Ktor. In issue https://github.com/ktorio/ktor/issues/1540#issuecomment-570062372, @qwwdfsad left a comment that this issue will cause continuations to resume twice (unexpected). Maybe that explains this as well?

kotlin.IllegalStateException: No more continuations to resume
        at 0   common                              0x000000010735b4e0 kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 92
        at 1   common                              0x0000000107354608 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 88
        at 2   common                              0x0000000107354044 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 88
        at 3   common                              0x0000000107354858 kfun:kotlin.IllegalStateException.<init>(kotlin.String?)kotlin.IllegalStateException + 88
        at 4   common                              0x00000001075cc794 kfun:io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith#internal + 1408
        at 5   common                              0x00000001075cc03c kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1188
        at 6   common                              0x00000001075cb71c kfun:io.ktor.util.pipeline.SuspendFunctionGun.proceed#internal + 352
        at 7   common                              0x00000001075cbad8 kfun:io.ktor.util.pipeline.SuspendFunctionGun.execute#internal + 412
        at 8   common                              0x00000001075c5328 kfun:io.ktor.util.pipeline.Pipeline.execute(TContext;TSubject)TSubject + 304
        at 9   common                              0x0000000107605f34 kfun:io.ktor.client.HttpClient.$executeCOROUTINE$1143.invokeSuspend(kotlin.Result<kotlin.Any?>)kotlin.Any? + 504
        at 10  common                              0x0000000107606200 kfun:io.ktor.client.HttpClient.execute(io.ktor.client.request.HttpRequestBuilder)io.ktor.client.call.HttpClientCall + 256
        at 11  common                              0x0000000107641568 kfun:io.ktor.client.statement.HttpStatement.$executeUnsafeCOROUTINE$1185.invokeSuspend(kotlin.Result<kotlin.Any?>)kotlin.Any? + 712
        at 12  common                              0x000000010764181c kfun:io.ktor.client.statement.HttpStatement.executeUnsafe$ktor-client-core()io.ktor.client.statement.HttpResponse + 212
        at 13  common                              0x0000000107b6dd24 kfun:com.superthomaslab.hueessentials.common.huesdk.bridge.hue.BridgeApi.$getDataStoreForceNetworkCOROUTINE$513.invokeSuspend(kotlin.Result<kotlin.Any?>)kotlin.Any? + 4260
        at 14  common                              0x0000000107b6eacc kfun:com.superthomaslab.hueessentials.common.huesdk.bridge.hue.BridgeApi.getDataStoreForceNetwork(kotlin.Boolean;kotlin.Boolean)io.ktor.utils.io.ByteReadChannel + 268
        at 15  common                              0x0000000107b6ec4c kfun:com.superthomaslab.hueessentials.common.huesdk.bridge.hue.BridgeApi.getDataStoreForceNetwork$default(kotlin.Boolean;kotlin.Boolean;kotlin.Int)io.ktor.utils.io.ByteReadChannel + 272
        at 16  common                              0x0000000107ac3c04 kfun:com.superthomaslab.hueessentials.common.huesdk.bridge.HeartbeatHelper.$createHeartbeat$lambda-0COROUTINE$336.invokeSuspend#internal + 4612
        at 17  common                              0x000000010737b238 kfun:kotlin.coroutines.native.internal.BaseContinuationImpl.resumeWith(kotlin.Result<kotlin.Any?>) + 524
        at 18  common                              0x00000001074cb660 kfun:kotlinx.coroutines.DispatchedTask.run() + 2284
        at 19  common                              0x0000000107505d10 kfun:kotlinx.coroutines.DarwinMainDispatcher.dispatch$lambda-0#internal + 112
        at 20  common                              0x00000001075060d0 kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$543.invoke#internal + 64
        at 21  common                              0x0000000107506130 kfun:kotlinx.coroutines.DarwinMainDispatcher.$dispatch$lambda-0$FUNCTION_REFERENCE$543.$<bridge-UNN>invoke()#internal + 64
        at 22  common                              0x00000001075071bc _6b6f746c696e782d636f726f7574696e65732d636f7265_knbridge828 + 188
        at 23  libdispatch.dylib                   0x000000010a9bdd10 _dispatch_call_block_and_release + 32
        at 24  libdispatch.dylib                   0x000000010a9bf18c _dispatch_client_callout + 20
        at 25  libdispatch.dylib                   0x000000010a9cdd14 _dispatch_main_queue_callback_4CF + 996
        at 26  CoreFoundation                      0x000000018d38f6b0 AF42303F-57B6-3C11-8F18-8E80ABF7D886 + 710320
        at 27  CoreFoundation                      0x000000018d38a2c8 AF42303F-57B6-3C11-8F18-8E80ABF7D886 + 688840
        at 28  CoreFoundation                      0x000000018d3898f4 CFRunLoopRunSpecific + 480
        at 29  GraphicsServices                    0x00000001977a0604 GSEventRunModal + 164

Furthermore, some logs I added show there are multiple network exceptions from Ktor before this crash occurs (kotlinx.coroutines.CancellationException: Socket timeout has been expired). That means the behaviour in my app is the same as this issue:

But when (performApiCall called from iOS, and) someApi.someMethod() throws some exception, then below crash happens:

Is there anything I can do to help? Users of my app are experiencing crashes due to this issue and I would really like to find a solution if that is possible.

It seems to be ktor-specific. I cannot figure out how to reproduce it in isolation.

This was happening to me when I was passing a massive string into the builder. Unsure if that helps.

Looks like this issue is fixed with Kotlin Coroutines 1.3.7-native-mt-1.4-M2 and Ktor 1.3.2-1.4-M2.

Closing as fixed

@qwwdfsad Getting the same crash with ktor 1.4.1 and coroutines 1.3.9-native-mt-2. How can we fix it?

Got the same error as well when implementing a suspending function in iOS code (KotlinSuspendFunction1) when calling the completion handler.

However, looking at the source code, CoroutineDispatcher.kt, line 103 (macosx64):

@InternalCoroutinesApi
    public override fun releaseInterceptedContinuation(continuation: Continuation<*>) {
        (continuation as DispatchedContinuation<*>).reusableCancellableContinuation?.detachChild()
    }

Why not make this cast optional? Seems a bit dangerous to perform a forced downcast like that?

This cast cannot be made optional because it is supposed to always succeed.
When releaseInterceptedContinuation is invoked on the dispatcher that is different from the one that intercepted it, it only can indicate that some internal invariant is broken. It's better to fail fast in such situations instead of silently ignoring it (=> being silently buggy and inconsistent).

If the issue still persist with 1.3.9-native-mt-2, please create a separate issue with a reproducing project/test

2413 seems related, I was able to reproduce with KTor 1.4.2 or 1.4.3, but the issue went away when downgrading to 1.4.1 (all versions use coroutines 1.3.9-native-mt-2):

CI run with 1.4.1: https://github.com/floscher/ktor-ClassCastException/runs/1590236500?check_suite_focus=true#step:4:14045
CI run with 1.4.2: https://github.com/floscher/ktor-ClassCastException/runs/1590216930?check_suite_focus=true#step:4:10133
CI run with 1.4.3: https://github.com/floscher/ktor-ClassCastException/runs/1589576823?check_suite_focus=true#step:4:10133

It occurs when writing more than ~4090 Bytes in call.respondTextWriter().

Was this page helpful?
0 / 5 - 0 ratings