Hi. What could be the root cause of `IllegalStateE...
# compose
s
Hi. What could be the root cause of
IllegalStateException: LayoutNode should be attached to an owner
(see comments for more info)
I have a
LazyRow
with about 50 items. Each item consists of an image as well as 3 icons. When I use
animateScrollToItem(idx)
, I get following excepion:
Copy code
java.lang.IllegalStateException: LayoutNode should be attached to an owner
        at androidx.compose.ui.node.LayoutNodeKt.requireOwner(LayoutNode.kt:1433)
        at androidx.compose.ui.node.ModifierLocalConsumerNode.notifyConsumerOfChanges(ModifierLocalConsumerNode.kt:42)
        at androidx.compose.ui.node.ModifierLocalConsumerNode.access$notifyConsumerOfChanges(ModifierLocalConsumerNode.kt:23)
        at androidx.compose.ui.node.ModifierLocalConsumerNode$Companion$onReadValuesChanged$1.invoke(ModifierLocalConsumerNode.kt:49)
        at androidx.compose.ui.node.ModifierLocalConsumerNode$Companion$onReadValuesChanged$1.invoke(ModifierLocalConsumerNode.kt:48)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver$ApplyMap.callOnChanged(SnapshotStateObserver.kt:272)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver.callOnChanged(SnapshotStateObserver.kt:215)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver.access$callOnChanged(SnapshotStateObserver.kt:24)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver$applyObserver$1$2.invoke(SnapshotStateObserver.kt:43)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver$applyObserver$1$2.invoke(SnapshotStateObserver.kt:42)
        at androidx.compose.ui.platform.AndroidComposeView$snapshotObserver$1.invoke(AndroidComposeView.android.kt:268)
        at androidx.compose.ui.platform.AndroidComposeView$snapshotObserver$1.invoke(AndroidComposeView.android.kt:266)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver$applyObserver$1.invoke(SnapshotStateObserver.kt:42)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver$applyObserver$1.invoke(SnapshotStateObserver.kt:26)
        at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot(Snapshot.kt:1446)
        at androidx.compose.runtime.snapshots.SnapshotKt.takeNewSnapshot(Snapshot.kt:1456)
        at androidx.compose.runtime.snapshots.SnapshotKt.access$takeNewSnapshot(Snapshot.kt:1)
        at androidx.compose.runtime.snapshots.GlobalSnapshot.takeNestedSnapshot(Snapshot.kt:1132)
        at androidx.compose.runtime.snapshots.Snapshot$Companion.takeSnapshot(Snapshot.kt:230)
        at androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$snapshotFlow$1.invokeSuspend(SnapshotFlow.kt:150)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.flow.internal.SafeCollector.invokeSuspend(SafeCollector.kt:41)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
No exception happens if I use
scrollToItem(idx)
. I tried to reproduce the issue in a sample app, but was not able to. I also wasn't able to pinpoint what exact line of code causes the issue. My best guess is that it might be caused by the icons. Each of them is received as a flow similar to this:
Copy code
@Composable
private fun MyIcon() {
    val image by remember { getImageFlowSomhow() }.collectAsState(initial = null)

    image?.iconName?.let { iconName ->
        Image(
            rememberVectorPainter(image = Icons.Default.PlayArrow), // to be replaced with real icon
            contentDescription = "",
            Modifier
                .size(32.dp)
                .clickable { Log.e("tag", "MyIcon() ... clicked") }
        )
    }
}
Notes: - removing the flow and image null check fixes the issue - keeping the flow, but removing the
clickable{}
also fixes the issue Since there is more than one fix for the issue and flows are supposed to work as far as i know, my question: what could be the root cause for this exception? How can a compose node end up with no parent?
i
Can you try without the
let
? I.e., just using a local variable and an
if
check? There's been a few other threads I've seen about lets being a problem recently
s
aww, i already got my hopes up, but that's unfortunately not it. Still getting the same crash
i
Sounds like you have the makings of a nice simple sample project to attach to a bug - that kind of error is almost never a problem on your end, but something going wrong on the Compose side
a
also what compose version do you use?
s
OMG, I cannot believe it. I was trying for 2 straight day to pinpoint the issue in the code and never once thought about upgrading the compose version. Upgraded it now from
1.1.0-beta03
to
1.1.0-rc01
and the issue is gone.
🎉 1
thank you both a lot for reading and the help. i appreciate it.
a
yeah, I remember something similar being fixed recently