braze-android-sdk
braze-android-sdk copied to clipboard
[Bug]: Crash IllegalArgumentException in compose ContentCardsList
Braze Android SDK Version
30.4.0
Steps To Reproduce
Not able to reproduce, saw the crashes from Crashlytics
Expected Behavior
No crash
Actual Incorrect Behavior
Crash with IllegalArgumentException, stack trace attached
Fatal Exception: java.lang.IllegalArgumentException: Key "NjU0ZTBiNDRkZjc0YjkwMDRlMGQ3MDc0XyRfY2M9MzJkZTRlN2ItNmFlYy1jYThlLWNiOWQtYjljOGU1YzYyYjEzJmRpJmRtJm12PTY1NGUwYjQ0ZGY3NGI5MDA0ZTBkNzA3NiZvZCZwaT13ZnMmdz02NTRlMGI0NGRmNzRiOTAwNGUwZDcwMmYmd3A9MTcxNDE0NjkzMSZ3dj02NTRlMGI0NGRmNzRiOTAwNGUwZDczNmM=" was already used. If you are using LazyColumn/Row please make sure you provide a unique key for each item.
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(LayoutNodeSubcompositionsState.java:437)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:872)
at androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScopeImpl.measure-0kLqBqw(LazyLayoutMeasureScope.kt:125)
at androidx.compose.foundation.lazy.LazyListMeasuredItemProvider.getAndMeasure(LazyListMeasuredItemProvider.java:48)
at androidx.compose.foundation.lazy.LazyListMeasureKt.measureLazyList-5IMabDg(LazyListMeasure.kt:195)
at androidx.compose.foundation.lazy.LazyListKt$rememberLazyListMeasurePolicy$1$1.invoke-0kLqBqw(LazyList.kt:313)
at androidx.compose.foundation.lazy.LazyListKt$rememberLazyListMeasurePolicy$1$1.invoke(LazyList.kt:178)
at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$3$2$1.invoke-0kLqBqw(LazyLayout.kt:107)
at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$3$2$1.invoke(LazyLayout.kt:100)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$2.invoke-3p2s80s(AndroidOverscroll_android.kt:584)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$2.invoke(AndroidOverscroll_android.kt:583)
at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifier.kt:294)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$1.invoke-3p2s80s(AndroidOverscroll.android.kt:568)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$1.invoke(AndroidOverscroll.android.kt:567)
at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifier.kt:294)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
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:1617)
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:1145)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.java:1136)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded$default(MeasureAndLayoutDelegate.kt:491)
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:23303)
at android.view.View.updateDisplayListIfDirty(View.java:22151)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4593)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4566)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:682)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:688)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:786)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:4678)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4389)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3604)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2372)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9082)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1234)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1242)
at android.view.Choreographer.doCallbacks(Choreographer.java:902)
at android.view.Choreographer.doFrame(Choreographer.java:835)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1217)
at android.os.Handler.handleCallback(Handler.java:942)
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:8066)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:703)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
Verbose Logs
No response
Additional Information
No response
Can you let us know what parameters, if any, you're passing to ContentCardList()
?
We pass the parameters emptyComposable
, style
, cardStyle
, cardUpdateHandler
, onCardClicked
and customCardComposer
Can you send what you're passing for cardUpdateHandler
? If you don't want to post here, you can send it to Braze support.
Yes, sure
fun cardUpdateHandler(cards: List<Card>): List<Card> {
val cardComparator = Comparator { cardA: Card, cardB: Card ->
when {
// A displays above B since A is pinned and B isn't
cardA.isPinned && !cardB.isPinned -> -1
// B displays above A since B is pinned and A isn't
!cardA.isPinned && cardB.isPinned -> 1
// At this point, both A & B are pinned or both A & B are non-pinned
// A displays above B if A is newer
cardA.created > cardB.created -> -1
// B displays above A if B is newer
cardA.created < cardB.created -> 1
// They're considered equal at this point
else -> 0
}
}
return cards.sortedWith(cardComparator)
.onEach { card ->
card.isDismissibleByUser = false
}
}
OK. I'm not able to recreate it either, but I'm adding a fix that will prevent duplicate ID's, which shouldn't be occurring.
As a side note, you may want to update your cardUpdateHandler to filter cards that have containsInvalidBrazeAction()
just to match the default implementation.
@bryanlogan when are you planning to do the fix, We have the same crash reported as well
Release 32.0.0 fixes this issue if duplicate cards are passed in.
Issue still happens after upgrading the sdk to 32.0.0
Fatal Exception: java.lang.IllegalArgumentException: Key "NjZhOTA3Y2IxMDdkZmYxYzI0YTFlOTQwXyRfY2M9MTMwMGE3NGYtYTM0ZC0zOTRkLTlkZTktZjQwZGY3ZDdhMGQzJmRpJmRtJm12PTY2YTkwOGVkZmRjZjEwMDA1YzZjNmE2YyZvZCZwaT13ZnMmdz02NjM4OWM3YjJmNmFkZTAwNTk3NTc4ZGEmd3A9MTcyNTAwNTIyOSZ3dj02NjM4OWM3YzJmNmFkZTAwNTk3NTdhMDA=" was already used. If you are using LazyColumn/Row please make sure you provide a unique key for each item.
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(LayoutNodeSubcompositionsState.java:437)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:872)
at androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScopeImpl.measure-0kLqBqw(LazyLayoutMeasureScope.kt:125)
at androidx.compose.foundation.lazy.LazyListMeasuredItemProvider.getAndMeasure(LazyListMeasuredItemProvider.java:48)
at androidx.compose.foundation.lazy.LazyListMeasureKt.measureLazyList-5IMabDg(LazyListMeasure.kt:195)
at androidx.compose.foundation.lazy.LazyListKt$rememberLazyListMeasurePolicy$1$1.invoke-0kLqBqw(LazyList.kt:313)
at androidx.compose.foundation.lazy.LazyListKt$rememberLazyListMeasurePolicy$1$1.invoke(LazyList.kt:178)
at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$3$2$1.invoke-0kLqBqw(LazyLayout.kt:107)
at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$3$2$1.invoke(LazyLayout.kt:100)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$2.invoke-3p2s80s(AndroidOverscroll_android.kt:584)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$2.invoke(AndroidOverscroll_android.kt:583)
at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifier.kt:294)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$1.invoke-3p2s80s(AndroidOverscroll.android.kt:568)
at androidx.compose.foundation.AndroidOverscroll_androidKt$StretchOverscrollNonClippingLayer$1.invoke(AndroidOverscroll.android.kt:567)
at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifier.kt:294)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
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:1617)
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:1145)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.java:1136)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded$default(MeasureAndLayoutDelegate.kt:491)
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:23303)
at android.view.View.updateDisplayListIfDirty(View.java:22151)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4592)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4565)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4592)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4565)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4592)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4565)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4592)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4565)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4592)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4565)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4592)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4565)
at android.view.View.updateDisplayListIfDirty(View.java:22097)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:682)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:688)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:786)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:4685)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4396)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3611)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2380)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9150)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1234)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1242)
at android.view.Choreographer.doCallbacks(Choreographer.java:902)
at android.view.Choreographer.doFrame(Choreographer.java:835)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1217)
at android.os.Handler.handleCallback(Handler.java:942)
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:8061)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:703)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:923)
@mozarty Are you able to recreate this? We haven't been able to get clear recreation steps. In your case, are you seeing Card ID ___ already exists. Skipping card
in the logcat?
I can only see the report on crashlytics, I haven't seen it in my local sessions