-
Notifications
You must be signed in to change notification settings - Fork 11
Open
Labels
Description
- I have updated Purchases SDK to the latest version
- I have read
the Contribution Guidelines - I have searched the Community
- I have read docs.revenuecat.com
- I have searched
for existing Github issues
Describe the bug
Observed a rare crash in production that appears to be related to the initialization and usage of the Purchases.sharedInstance. This crash does not happen consistently—it occurs only occasionally and not during every user session.
Context:
- The Purchases SDK is initialized at app startup in the app’s main initialization flow.
- The only other place where Purchases.sharedInstance is accessed is the Paywall screen, which is only presented when the user manually triggers the premium flow (typically at least 5+ seconds after app launch).
- Despite this delay, the crash is being reported from the Paywall screen, suggesting a potential issue with either the timing of SDK initialization or how/when Purchases.sharedInstance is being accessed.
Here is the app init code
LaunchedEffect(Unit) {
Purchases.logLevel = LogLevel.INFO
Purchases.configure(apiKey = billing.apiKey()) {
}
Purchases.sharedInstance.getCustomerInfo(
onSuccess = { customerInfo ->
// do somehting
},
onError = {
}
)
}and here is the code from the paywall screen
val options = remember {
PaywallOptions(
dismissRequest = {
handleNavigation(false, coroutineScope, source, navController, localConfigRepository)
}
) {
shouldDisplayDismissButton = true
listener = object : PaywallListener {
override fun onPurchaseCancelled() {
super.onPurchaseCancelled()
println("-_- RC Purchase cancelled")
}
override fun onPurchaseCompleted(
customerInfo: CustomerInfo,
storeTransaction: StoreTransaction
) {
super.onPurchaseCompleted(customerInfo, storeTransaction)
println("-_- RC Purchase completed")
}
override fun onPurchaseError(error: PurchasesError) {
super.onPurchaseError(error)
println("-_- RC Purchase error")
}
override fun onPurchaseStarted(rcPackage: Package) {
super.onPurchaseStarted(rcPackage)
println("-_- RC Purchase started")
}
override fun onRestoreCompleted(customerInfo: CustomerInfo) {
super.onRestoreCompleted(customerInfo)
println("-_- RC Restore completed")
}
override fun onRestoreError(error: PurchasesError) {
super.onRestoreError(error)
println("-_- RC Restore error")
}
override fun onRestoreStarted() {
super.onRestoreStarted()
println("-_- RC Restore started")
}
}
}
}
Paywall(
options = options
)This issue has 2 crash events affecting 1 user
Stacktrace
Fatal Exception: A8.H: There is no singleton instance. Make sure you configure Purchases before trying to get the default instance. More info here: https://errors.rev.cat/configuring-sdk
at com.revenuecat.purchases.Purchases$Companion.getSharedInstance(Purchases.kt:11)
at com.revenuecat.purchases.ui.revenuecatui.data.PurchasesImpl.<init>(PurchasesType.kt:3)
at com.revenuecat.purchases.ui.revenuecatui.data.PaywallViewModelImpl.<init>(PaywallViewModel.kt:2)
at com.revenuecat.purchases.ui.revenuecatui.data.PaywallViewModelFactory.create(PaywallViewModelFactory.kt:23)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.android.kt:3)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.android.kt:1)
at androidx.lifecycle.viewmodel.ViewModelProviderImpl_androidKt.createViewModel(ViewModelProviderImpl.android.kt:16)
at androidx.lifecycle.viewmodel.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel_release(ViewModelProviderImpl.kt:57)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.android.kt:13)
at androidx.lifecycle.viewmodel.compose.ViewModelKt__ViewModelKt.get(ViewModel.kt:63)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:1)
at androidx.lifecycle.viewmodel.compose.ViewModelKt__ViewModelKt.viewModel(ViewModel.kt:79)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:1)
at com.revenuecat.purchases.ui.revenuecatui.InternalPaywallKt.getPaywallViewModel(InternalPaywall.kt:133)
at com.revenuecat.purchases.ui.revenuecatui.InternalPaywallKt.InternalPaywall(InternalPaywall.kt:123)
at com.revenuecat.purchases.ui.revenuecatui.PaywallKt.Paywall(Paywall.kt:60)
at com.revenuecat.purchases.kmp.ui.revenuecatui.PaywallKt.Paywall(Paywall.kt:31)
at com.sample.packagename.paywall.PaywallScreenRouteKt.PaywallScreenRoute(PaywallScreenRoute.kt:225)
at com.sample.packagename.MainScreenKt$MainScreenRoute$4$1$3$1$1$3.invoke(MainScreen.kt:119)
at com.sample.packagename.MainScreenKt$MainScreenRoute$4$1$3$1$1$3.invoke(MainScreen.kt:13)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:3)
at androidx.navigation.compose.NavHostKt$NavHost$32$1.invoke(NavHost.kt:2)
at androidx.navigation.compose.NavHostKt$NavHost$32$1.invoke(NavHost.kt:1)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:1)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:31)
at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:175)
at androidx.navigation.compose.NavBackStackEntryProviderKt.SaveableStateProvider(NavBackStackEntryProvider.kt:140)
at androidx.navigation.compose.NavBackStackEntryProviderKt.access$SaveableStateProvider(NavBackStackEntryProvider.kt:1)
at androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke(NavBackStackEntryProvider.kt:2)
at androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke(NavBackStackEntryProvider.kt:1)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:1)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:31)
at androidx.navigation.compose.NavBackStackEntryProviderKt.LocalOwnersProvider(NavBackStackEntryProvider.kt:130)
at androidx.navigation.compose.NavHostKt$NavHost$32.invoke(NavHost.kt:85)
at androidx.navigation.compose.NavHostKt$NavHost$32.invoke(NavHost.kt:13)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:3)
at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1$5.invoke(AnimatedContent.kt:2)
at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1$5.invoke(AnimatedContent.kt:1)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:2)
at androidx.compose.animation.AnimatedVisibilityKt.AnimatedEnterExitImpl(AnimatedVisibility.kt:1)
at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1.invoke(AnimatedContent.kt:2)
at androidx.compose.animation.AnimatedContentKt$AnimatedContent$6$1.invoke(AnimatedContent.kt:1)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:1)
at androidx.compose.animation.AnimatedContentKt.AnimatedContent(AnimatedContent.kt:888)
at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:1)
at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:1)
at com.sample.packagename.MainScreenKt$MainScreenRoute$4$1$3.invoke(MainScreen.kt:200)
at com.sample.packagename.MainScreenKt$MainScreenRoute$4$1$3.invoke(MainScreen.kt:11)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:2)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayout$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:2)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayout$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:1)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:1)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(SubcomposeLayout.kt:2)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(SubcomposeLayout.kt:1)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:45)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:1)
at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:18)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:1)
at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:14)
at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:16)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:25)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:7)
at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:16)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:1)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto(SubcomposeLayout.kt:15)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:55)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:59)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:169)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:3)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayout$1$1.invoke-0kLqBqw(Scaffold.kt:1)
at androidx.compose.material3.ScaffoldKt$ScaffoldLayout$1$1.invoke(Scaffold.kt:9)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:113)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:73)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:2)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:69)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:46)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:96)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:3)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:11)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:40)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:147)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:60)
at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:73)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:73)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:1)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:45)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:2)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:69)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:46)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:96)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:3)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:11)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:40)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:147)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:60)
at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:73)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:73)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:1)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:45)
at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:99)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:45)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:2)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:69)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:46)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:96)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:3)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:11)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:40)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:147)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:60)
at androidx.compose.ui.layout.RootMeasurePolicy.measure-3p2s80s(RootMeasurePolicy.kt:41)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:73)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:2)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:130)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:46)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:96)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:3)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:11)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:40)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:147)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:20)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:5)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureOnly(MeasureAndLayoutDelegate.kt:25)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureOnly(MeasureAndLayoutDelegate.kt:86)
at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:106)
at android.view.View.measure(View.java:24726)
at androidx.compose.ui.platform.AbstractComposeView.internalOnMeasure$ui_release(ComposeView.android.kt:64)
at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:4)
at android.view.View.measure(View.java:24726)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6931)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:24726)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6931)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:24726)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6931)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:746)
at android.view.View.measure(View.java:24726)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3184)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1952)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2252)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1840)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7937)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:980)
at android.view.Choreographer.doCallbacks(Choreographer.java:804)
at android.view.Choreographer.doFrame(Choreographer.java:739)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:965)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:264)
at android.app.ActivityThread.main(ActivityThread.java:7663)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
FYI using KMP purchase version
purchases-kmp = "1.7.1+13.25.0"
# This version must be equal to everything after the '+' in the purchases-kmp version
purchases-common = "13.25.0"
- Environment
- Platform: Compose Multiplatform
- SDK version:
- AGP: 8.5.2
- Kotlin: 2.1.0
- OS version: Sonoma 14.6.1 (23G93)
- IDE (e.g. Android Studio, Xcode, Fleet): Android
- IDE version: Android Studio Meerkat | 2024.3.1
- Device and/or emulator/simulator:
- Device
- Emulator/simulator
- Environment:
- Closed testing / Sandbox
- TestFlight
- Production
- How widespread is the issue. Percentage of devices affected.
- Debug logs that reproduce the issue
- Steps to reproduce, with a description of expected vs. actual behavior
- Other information (e.g. stacktraces, related issues, suggestions how to fix, links for us to
have context, eg. stackoverflow, etc.)
Additional context
Add any other context about the problem here.
Reactions are currently unavailable