Skip to content
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

wasmJs: The operation was aborted. #2860

Open
julius-b opened this issue Feb 21, 2025 · 1 comment
Open

wasmJs: The operation was aborted. #2860

julius-b opened this issue Feb 21, 2025 · 1 comment

Comments

@julius-b
Copy link

julius-b commented Feb 21, 2025

Describe the bug
I'm not certain but I think there is a problem with Coil and the way it acts when the image loading is cancelled by AsyncImage moving out of scope, specifically on wasmJs. Using the circuit navigation library, when changing the Screen (effectively the @Composable) from a LaunchedEffect while the current AsyncImage is still loading, this exception occurs (app/website crash):

Uncaught runtime errors:
ERROR
The operation was aborted. 
io.ktor.client.fetch.abort_$external_fun@webpack-internal:///./kotlin/composeApp.uninstantiated.mjs:4645:73
<CoilBug:composeApp>.io.ktor.client.engine.js.JsClientEngine$execute$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[59948]:0x761a81
<CoilBug:composeApp>.io.ktor.client.engine.js.JsClientEngine$execute$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[59949]:0x761aa9
<CoilBug:composeApp>.kotlinx.coroutines.InvokeOnCancelling.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15857]:0x3c6146
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.notifyCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15773]:0x3c33df
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15816]:0x3c53e1
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCompleting@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15815]:0x3c5202
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelMakeCompleting@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15806]:0x3c495c
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelImpl@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15805]:0x3c4847
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelInternal@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15801]:0x3c47c1
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancel@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15798]:0x3c46ed
<CoilBug:composeApp>.io.ktor.client.engine.createCallContext$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[58743]:0x749a64
<CoilBug:composeApp>.io.ktor.client.engine.createCallContext$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[58744]:0x749a8d
<CoilBug:composeApp>.kotlinx.coroutines.InvokeOnCancelling.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15857]:0x3c6146
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.notifyCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15773]:0x3c33df
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15812]:0x3c4fed
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.makeCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15810]:0x3c4e5b
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelImpl@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15805]:0x3c4865
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.parentCancelled@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15802]:0x3c47d7
<CoilBug:composeApp>.kotlinx.coroutines.ChildHandleNode.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15867]:0x3c62c8
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.notifyCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15773]:0x3c33df
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15812]:0x3c4fed
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.makeCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15810]:0x3c4e5b
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelImpl@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15805]:0x3c4865
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.parentCancelled@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15802]:0x3c47d7
<CoilBug:composeApp>.kotlinx.coroutines.ChildHandleNode.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15867]:0x3c62c8
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.notifyCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15773]:0x3c33df
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15812]:0x3c4fed
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.makeCancelling@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15810]:0x3c4e5b
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelImpl@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15805]:0x3c4865
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelInternal@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15801]:0x3c47c1
<CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancel@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15798]:0x3c46ed
<CoilBug:composeApp>.kotlinx.coroutines.Job.cancel$default@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[15629]:0x3c0e05
<CoilBug:composeApp>.coil3.compose.AsyncImagePainter.<set-rememberJob>@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[54479]:0x6f7de0
<CoilBug:composeApp>.coil3.compose.AsyncImagePainter.onForgotten@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[54509]:0x6f8232
<CoilBug:composeApp>.coil3.compose.internal.ContentPainterNode.onDetach@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[54661]:0x6fb8c2
<CoilBug:composeApp>.androidx.compose.ui.Node.runDetachLifecycle@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[33895]:0x53c2d1
<CoilBug:composeApp>.androidx.compose.ui.node.NodeChain.runDetachLifecycle@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[37874]:0x59b6a2
<CoilBug:composeApp>.androidx.compose.ui.node.LayoutNode.detach@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[37095]:0x587d6d
<CoilBug:composeApp>.androidx.compose.ui.node.LayoutNode.detach@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[37095]:0x587def
<CoilBug:composeApp>.androidx.compose.ui.node.LayoutNode.detach@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[37095]:0x587def
<CoilBug:composeApp>.androidx.compose.ui.node.LayoutNode.onChildRemoved@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[37088]:0x587382
<CoilBug:composeApp>.androidx.compose.ui.node.LayoutNode.removeAt@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[37086]:0x58728d
<CoilBug:composeApp>.androidx.compose.ui.platform.DefaultUiApplier.remove@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[40207]:0x5be628
<CoilBug:composeApp>.androidx.compose.runtime.changelist.RemoveNode.execute@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[23286]:0x4425a8
<CoilBug:composeApp>.androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[23451]:0x445e15
<CoilBug:composeApp>.androidx.compose.runtime.changelist.ChangeList.executeAndFlushAllPendingChanges@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[23043]:0x4384da
<CoilBug:composeApp>.androidx.compose.runtime.CompositionImpl.applyChangesInLocked@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[21704]:0x41440e
<CoilBug:composeApp>.androidx.compose.runtime.CompositionImpl.applyChanges@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[21705]:0x414a1d
<CoilBug:composeApp>.androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$slambda$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[22044]:0x41e59b
<CoilBug:composeApp>.androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$slambda$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[22045]:0x41ed2e
<CoilBug:composeApp>.androidx.compose.runtime.FrameAwaiter.resume@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[21102]:0x401dc4
<CoilBug:composeApp>.androidx.compose.runtime.BroadcastFrameClock.sendFrame@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[21120]:0x402476
<CoilBug:composeApp>.androidx.compose.ui.scene.BaseComposeScene.render@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[40650]:0x5c5b05
<CoilBug:composeApp>.androidx.compose.ui.window.<no name provided>.onRender@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[41315]:0x5d254f
<CoilBug:composeApp>.org.jetbrains.skiko.<no name provided>.drawFrame@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[28896]:0x4c4d98
<CoilBug:composeApp>.org.jetbrains.skiko.CanvasRenderer$needRedraw$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[28863]:0x4c4718
<CoilBug:composeApp>.org.jetbrains.skiko.CanvasRenderer$needRedraw$lambda.invoke@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[28864]:0x4c4771
<CoilBug:composeApp>.org.w3c.dom.__callFunction_((Double)->Unit)@http://localhost:8080/aa701647711f341d29ed.wasm:wasm-function[18326]:0x3f152f
org.w3c.dom.__convertKotlinClosureToJsClosure_((Double)->Unit)/<@webpack-internal:///./kotlin/composeApp.uninstantiated.mjs:1195:124

To Reproduce
Here is a very simple repository to reproduce: https://github.com/julius-b/coil-bug
It's basically just an AsyncImage: https://github.com/julius-b/coil-bug/blob/main/composeApp/src/wasmJsMain/kotlin/ch/whatever/MainScreen.kt#L69
LaunchedEffect that cancels the AsyncImage: https://github.com/julius-b/coil-bug/blob/main/composeApp/src/wasmJsMain/kotlin/ch/whatever/App.kt#L30

The demo loads 20 images which increases the chance of this bug occurring to about every 2nd page reload.
note: In this sample, the bug can be prevented by changing whether the initial screen is even shown, which makes it so that the image loading is never cancelled.

NOTE: in this demo, the bug only occurs when the QuizView (Screen) also uses AsyncImage, but in the project where I noticed this issue the QuizView does not use AsyncImage and the bug still occurs.
Also the bug is significantly rarer in Chromium (^ report was with Firefox) and the Stacktrace there is differnt:

Uncaught runtime errors:
×
ERROR
BodyStreamBuffer was aborted
AbortError: BodyStreamBuffer was aborted
    at io.ktor.client.fetch.abort_$external_fun (webpack-internal:///./kotlin/composeApp.uninstantiated.mjs:4645:73)
    at <CoilBug:composeApp>.io.ktor.client.engine.js.JsClientEngine$execute$lambda.invoke (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[59948]:0x761a81)
    at <CoilBug:composeApp>.io.ktor.client.engine.js.JsClientEngine$execute$lambda.invoke (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[59949]:0x761aa9)
    at <CoilBug:composeApp>.kotlinx.coroutines.InvokeOnCancelling.invoke (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15857]:0x3c6146)
    at <CoilBug:composeApp>.kotlinx.coroutines.JobSupport.notifyCancelling (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15773]:0x3c33df)
    at <CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15816]:0x3c53e1)
    at <CoilBug:composeApp>.kotlinx.coroutines.JobSupport.tryMakeCompleting (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15815]:0x3c5202)
    at <CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelMakeCompleting (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15806]:0x3c495c)
    at <CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelImpl (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15805]:0x3c4847)
    at <CoilBug:composeApp>.kotlinx.coroutines.JobSupport.cancelInternal (http://localhost:8080/5bf60037f095d0dccd78.wasm:wasm-function[15801]:0x3c47c1)

(similar to #2462)

Version
coil = "3.1.0"
compose-multiplatform = "1.7.3"
kotlin = "2.1.10"
ktor = "3.0.3"

@colinrtwhite
Copy link
Member

Hmm considering this only occurs on wasmJs I think this is likely either be a wasm JS Kotlin compiler bug or bug in the Chromium/Firefox runtime. Coil doesn't have much wasm JS specific code and relies on common code entirely for the Compose integration. I'm not sure if there's anything we can do on Coil's end to work around this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants