-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fatal ClassCastException in CoroutineDispatcher#releaseInterceptedContinuation #3773
Comments
Is it possible to pinpoint the exact place that happens to fail in API wrapper? Maybe an entry-point? |
It seemed to be happening on REST requests at random. I will stress test it more later today and report back anything I can find. |
Actually, I had a bit to test out a function that had seemed particularly problematic to me the other day. The function is basically this: context(Foo)
suspend fun Bar.close() {
// these behaviours come from Kord, the third-party library
// "user" and "channel" are fields of Bar.
val userBehavior = UserBehavior(user, kord)
val channelBehavior = MessageChannelBehavior(channel, kord)
// does a POST request
userBehavior.getDmChannel().createEmbed { ... }
// does another POST request
// "config" and "kord" come from Foo. The latter is a Kord object.
kord.rest.channel.createMessage(config.stuff) { ... }
// does a DELETE request
channelBehaviour.delete()
// does an update on a CoroutineCollection from KMongo
// "collection" comes from Foo
collection.updateOne(...)
} The exception seems to be fairly consistently thrown here. And what's even more curious, is that I tried putting a breakpoint in each of those four calls and debugging the problem, to see exactly which one made it, and it turns out it appeared after I continued on the KMongo call, and the function exited. Any suggestions on how to further debug this? |
Could you please see if the following workaround helps? |
I've tried some tests. |
Poked around some more and eventually got the bugger to appear again (in a completely different spot, as expected). Unfortunately, adding that property define didn't help. Both with and without Ktor's SFG, the error persists. |
Thank you, we'll start looking into it more extensively. The biggest problem here is the scope --
I'm not sure which one it is here. Based on the anecdotical evidence (i.e. the stream of reports) I have regarding this very CCE -- if it reproduces without SFG (which is, on its own, quite an unpleasant beast), it might be the problem with context receivers -- they are preview feature and might have tricky problems. I suggest doing the following:
Sorry for such a long list, though! With such information, we might be able to hand-craft the similar "reproducer" manually and just study the bytecode about potential miscompilations |
Thank you for your response! Will try to get all that info as soon as I'm able to. In the meanwhile, I forgot to mention a little detail regarding yesterday's testing: the exception, although very very similar, has changed slightly:
I'm unsure if this helps trace the error in any way. |
First of all, with a bit more poking around, I managed to get the bug to appear on that close function again, while also manifesting itself on the new location, quite consistently.
I hacked together a context receiver free thingy, and indeed it completely fixed the problem on both locations.
Here's a more detailed view of that function: context(Foo)
suspend fun Bar.close() {
val userBehavior = UserBehavior(user, kord) // constructor
val channelBehavior = MessageChannelBehavior(channel, kord) // constructor
runCatching {
userBehavior.getDmChannel().createEmbed { // suspend inline
// it's just setting some properties
}
}
// tries getting from cache, might do a REST call
val user = userBehavior.asUserOrNull() // suspend
config.stuff.createMessage { // suspend inline;
// extension function, "alias" for kord.rest.channel.createMessage, also a suspend inline fun;
// context receiver is Foo
channelBehaviour.someExtensionFunc() // suspend
// some more property setting
}
channelBehaviour.delete() // suspend
collection.updateByChannel(...) // suspend; extension function on CoroutineCollection that does some base filtering
} There are no As for the second location, it's a simple function that does a REST call and sets up a callback. Nothing in it gets run, the exception is always thrown right at the beginning. |
Thanks! It's definitely a compiler bug, I've checked the YT tracker, and it seems to be it: https://youtrack.jetbrains.com/issue/KT-53551 |
Alright, thank you! In the meantime, I suppose I can fix this by avoiding context receivers on suspend functions. |
Describe the bug
I've been getting the following exception from a third-party library using Ktor, seemingly at random:
(obtained with coroutine debug mode enabled)
After looking at kx.coro's code, I found
ContinuationImpl#releaseIntercepted
must be called twice, thus callingCoroutineDispatcher#releaseInterceptedContinuation
, which results in aClassCastException
. By that linked comment, this should only happen in case of a compiler bug.I'm using Kotlin 1.8.20, kotlinx.coroutines 1.7.1 and Ktor 2.3.0.
Provide a Reproducer
Due to the seemingly random nature of this bug's appearances, and the fact my codebase is quite large and doesn't even interact with Ktor directly (but rather through an API wrapper), I can't spot the culprit and provide a minimally working reproducer. I've also asked around in that wrapper's support channels and nobody has gotten any similar error, so I doubt the issue stems from it.
PS: I have submitted a bug report on Kotlin's YouTrack board, because the comment said it was a compiler bug, however someone advised me to post it on this tracker as well: https://youtrack.jetbrains.com/issue/KT-59090/Fatal-exception-in-coroutines-machinery-for-DispatchedContinuation-in-Ktor-HttpClientexecute
The text was updated successfully, but these errors were encountered: