Im looking into a `Detected multithreaded access t...
# compose
z
Im looking into a
Detected multithreaded access to SnapshotStateObserver
crash in production. Any ideas on where to look? Afaik, Im not doing any fancy stuff off the main thread with compose. Full stack trace in 🧵
Copy code
Fatal Exception: java.lang.IllegalArgumentException: Detected multithreaded access to SnapshotStateObserver: previousThreadId=167), currentThread={id=2, name=main}. Note that observation on multiple threads in layout/draw is not supported. Make sure your measure/layout/draw for each Owner (AndroidComposeView) is executed on the same thread.
       at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:241)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:1613)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:36)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
       at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.java:1144)
       at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.java:1135)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:509)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.onlyRemeasureIfScheduled(MeasureAndLayoutDelegate.kt:593)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:619)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtree(MeasureAndLayoutDelegate.kt:582)
       at androidx.compose.ui.platform.AndroidComposeView.forceMeasureTheSubtree(AndroidComposeView.android.kt:993)
       at androidx.compose.ui.node.Owner.forceMeasureTheSubtree$default(Owner.java:239)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:632)
       at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.java:1144)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:354)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureOnly(MeasureAndLayoutDelegate.kt:557)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureOnly(MeasureAndLayoutDelegate.kt:407)
       at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:1058)
       at android.view.View.measure(View.java:26207)
       at androidx.compose.ui.platform.AbstractComposeView.internalOnMeasure$ui_release(ComposeView.android.kt:302)
       at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:289)
       at android.view.View.measure(View.java:26207)
       at androidx.compose.ui.viewinterop.AndroidViewHolder.onMeasure(AndroidViewHolder.android.kt:242)
       at android.view.View.measure(View.java:26207)
       at androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$5.measure-3p2s80s(AndroidViewHolder.android.kt:397)
       at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:252)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.java:251)
       at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.java:2303)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
       at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
       at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:1613)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.java:36)
       at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
       at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.java:1144)
       at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.java:1135)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:509)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded$default(MeasureAndLayoutDelegate.kt:486)
       at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:377)
       at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout(AndroidComposeView.android.kt:971)
       at androidx.compose.ui.node.Owner.measureAndLayout$default(Owner.java:228)
       at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:1224)
       at android.view.View.draw(View.java:23016)
       at android.view.View.updateDisplayListIfDirty(View.java:21880)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4526)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4499)
       at android.view.View.updateDisplayListIfDirty(View.java:21833)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4526)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4499)
       at android.view.View.updateDisplayListIfDirty(View.java:21833)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4526)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4499)
       at android.view.View.updateDisplayListIfDirty(View.java:21833)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4526)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4499)
       at android.view.View.updateDisplayListIfDirty(View.java:21833)
       at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:534)
       at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:542)
       at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:625)
       at android.view.ViewRootImpl.draw(ViewRootImpl.java:4645)
       at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4363)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3474)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2265)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9009)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1142)
       at android.view.Choreographer.doCallbacks(Choreographer.java:946)
       at android.view.Choreographer.doFrame(Choreographer.java:875)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1127)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:210)
       at android.os.Looper.loop(Looper.java:299)
       at android.app.ActivityThread.main(ActivityThread.java:8250)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
s
Try to obtain thread dump and check which thread corresponds with the given id. Likely it is using some semantics APIs or draws on that thread. Unfortunately it is a bit annoying to obtain the thread name in this case from runtime, so we cannot include this in the crash message
z
Good idea, but I cant obtain it 😞 Its just a single crash for now, I thought Id see an increase as more people adopted the release .. seems to not be the case though. If theres anything else you think could hint at where/why the crash happens, please let me know!
s
Might be device specific, we had issues with some devices accessing views on background thread ¯\_(ツ)_/¯
z
very nice
It was some odd device in my case as well, cant recall the model name even. Guess Ill leave it be for now 😃
z
Which version of compose did you see this on?
We’ve got some tests flaking with the same exception, I wonder if we’ve got a race condition somewhere in prod code: https://issuetracker.google.com/317749301
Can you file a bug for this even if you don’t have any more info @Zoltan Demant?
z
1.6.0-beta03
. I filed a bug here. I mentioned it there as well, but pretty sure its a new thing from a recent compose release, at least I havent seen it earlier.
s
The exception is new, as we added multithreading detection for this particular place It was crashing with a NullPointerException in SnapshotStateObserver before
z
14 crashes in total in the last 90 days then 👍
m
Any news? Got same issue when running UI automated tests ;/
271 Views