compose-multiplatform: Crash "LayoutNode should be attached to an owner"
Describe the bug
I have a column with a list created from a for loop.
Each item in the list is wrapped with a call to key
. This follows the example in the official docs for key
here
Each item is a button that allows removing its own item from the list.
When using this, whether it works correctly or not depends on the speed of how fast you remove items. If you remove them slowly, it will work perfectly as expected. But, if you hover your mouse over the first button and rapidly click to remove them, you will get the following error. The exception seems to be handled internally and is not raised to the user. However, it is printed to the console, indicating to the developer that something is wrong.
java.lang.IllegalStateException: LayoutNode should be attached to an owner
at androidx.compose.ui.node.LayoutNodeKt.requireOwner(LayoutNode.kt:1448)
at androidx.compose.ui.node.LayoutNode.getCollapsedSemantics$ui(LayoutNode.kt:421)
at androidx.compose.ui.semantics.SemanticsNodeKt.SemanticsNode(SemanticsNode.kt:48)
at androidx.compose.ui.semantics.SemanticsNode.fillOneLayerOfSemanticsWrappers(SemanticsNode.kt:252)
at androidx.compose.ui.semantics.SemanticsNode.fillOneLayerOfSemanticsWrappers(SemanticsNode.kt:254)
at androidx.compose.ui.semantics.SemanticsNode.unmergedChildren$ui(SemanticsNode.kt:236)
at androidx.compose.ui.semantics.SemanticsNode.unmergedChildren$ui$default(SemanticsNode.kt:229)
at androidx.compose.ui.semantics.SemanticsNode.findOneLayerOfMergingSemanticsNodes(SemanticsNode.kt:343)
at androidx.compose.ui.semantics.SemanticsNode.findOneLayerOfMergingSemanticsNodes$default(SemanticsNode.kt:340)
at androidx.compose.ui.semantics.SemanticsNode.getChildren(SemanticsNode.kt:307)
at androidx.compose.ui.semantics.SemanticsNode.getReplacedChildren$ui(SemanticsNode.kt:281)
at androidx.compose.ui.platform.ComposeAccessible$ComposeAccessibleComponent.getAccessibleChildrenCount(ComposeAccessible.kt:299)
at java.desktop/sun.lwawt.macosx.CAccessibility$23.call(CAccessibility.java:486)
at java.desktop/sun.lwawt.macosx.CAccessibility$23.call(CAccessibility.java:470)
at java.desktop/sun.lwawt.macosx.LWCToolkit$CallableWrapper.run(LWCToolkit.java:698)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:308)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Affected platforms
- Desktop
I have only tested Desktop. This may happen on other platforms as well, but I have not checked.
Versions
- Kotlin version*: 1.9.20-Beta2
- Compose Multiplatform version*: Gradle plugin version 1.5.10-beta01, compiler version 1.5.2.1-Beta2
- OS version(s)* (required for Desktop and iOS issues): MacOs 13.5.2
- OS architecture (x86 or arm64): arm64
- JDK (for desktop issues): Temurin 18
To Reproduce
- Copy the code below, in a project with the versions above
- Run the application
- Hover your mouse of “Remove 1”
- Slowly click the button once per second until all buttons are gone
- Observe that there is no error
- Restart the app
- Repeat steps 3 and 4, but this time click as rapidly as you can
- Observe the error output with the IllegalStateException that was thrown
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
fun main() {
val list = mutableStateListOf(*(1..10).toList().toTypedArray())
application {
Window(visible = true, onCloseRequest = {
exitApplication()
}) {
Column {
for (i in list) {
key(i) {
Button(
onClick = { list.remove(i) }
) {
Text("Remove $i")
}
}
}
}
}
}
}
Expected behavior
There should not be an error.
About this issue
- Original URL
- State: closed
- Created 9 months ago
- Reactions: 1
- Comments: 25 (5 by maintainers)
Yes, I am dealing with this issue now.
From what I see, the way to reproduce this issue is
AnimatedVisibility
I can see the same issue happening, but I don’t know if it relates to my usage.
PR that contains this bug: https://github.com/lihenggui/blocker/pull/377/files
Eventually i found out that the problem is in the alpha version of androidx.compose.material3:material3:1.2.0. on version 1.1.2 i could not reproduce the bug
I am also experiencing the same problem on Android. Kotlin version 1.9.10, compose version 1.5.1. Is there any action on Android other than the desktop platform?
This bug also occurs in the original version of Compose.
I tried the latest material3 1.2.0-alpha10 and the problem disappear in my case. Previously used 1.2.0-alpha07