Encountered a java.lang.StackOverflowError
while attempting to retrieve data using Hawk. This crash occurs consistently when trying to access a specific value. The stack trace suggests the issue originates within the MqttUtf8StringImpl.toString()
method, which is repeatedly called, leading to the stack overflow. It appears Hawk is attempting to convert a value stored (or referenced by) Hawk to a String, and that is leading to the infinite loop.
Important Note: This crash is occurring in our production environment. While the crash occurs consistently in the described context within my application in production, I have been unable to reproduce this issue in a simplified, isolated test case, or even in a development/staging environment.
Stack Trace:
Fatal Exception: java.lang.StackOverflowError: stack size 8188KB
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString(MqttUtf8StringImpl.java:314)
at java.lang.String.valueOf(String.java:4102)
at java.lang.StringBuilder.append(StringBuilder.java:179)
at com.orhanobut.hawk.DefaultHawkFacade.get(DefaultHawkFacade.java:111)
at com.orhanobut.hawk.Hawk.get(Hawk.java:52)
at cab.app.appSharePrefModule.SharedPreferencesManager.get(SharedPreferencesManager.java:58)
at cab.app.driver.auth.units.otp.timer.OtpTimeManager.getOtpResponse(OtpTimeManager.kt:49)
at cab.app.driver.auth.units.otp.OTPInteractor.goToOtpIfHasTime(OTPInteractor.kt:155)
at cab.app.driver.auth.units.otp.OTPInteractor.onAttach(OTPInteractor.kt:136)
at cab.app.arch2.android.AndroidRouter.onInteractorAttach(AndroidRouter.kt:285)
at cab.app.arch2.androidpose.ComposeRouter.onInteractorAttach(ComposeRouter.kt:59)
at cab.app.arch2.android.AndroidRouter.onAttach(AndroidRouter.kt:280)
at cab.app.arch2.android.AndroidRouter.callInteractorAttach(AndroidRouter.kt:332)
at cab.app.arch2.android.AndroidRouter.attachChild(AndroidRouter.kt:324)
at cab.app.arch2.androidpose.ComposeRouter.attachChild(ComposeRouter.kt:64)
at cab.app.arch2.androidpose.ComposeRouter.attachChild(ComposeRouter.kt:89)
at cab.app.arch2.androidpose.ComposeRouter.attachChild(ComposeRouter.kt:82)
at cab.app.driver.auth.units.loggedout.LoggedOutRouter.attachOTP(LoggedOutRouter.kt:38)
at cab.app.driver.auth.units.loggedout.LoggedOutInteractor.mobileNumberClicked(LoggedOutInteractor.kt:144)
at cab.app.driver.auth.units.loggedout.LoggedOutInteractor.access$mobileNumberClicked(LoggedOutInteractor.kt:17)
at cab.app.driver.auth.units.loggedout.LoggedOutInteractor$collectEvents$1.emit(LoggedOutInteractor.kt:125)
at cab.app.driver.auth.units.loggedout.LoggedOutInteractor$collectEvents$1.emit(LoggedOutInteractor.kt:120)
at kotlinx.coroutines.flow.SharedFlowImpl.collect$suspendImpl(SharedFlow.kt:382)
at kotlinx.coroutines.flow.SharedFlowImpl$collect$1.invokeSuspend(SharedFlow.kt:13)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoopmon.kt:68)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:375)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Buildersmon.kt:56)
at kotlinx.coroutines.BuildersKt.launch(Builders.kt:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Buildersmon.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Builders.kt:1)
at baly.app.mvi.PresenterHandlerImpl.handleEvent(PresenterHandlerImpl.kt:19)
at cab.app.driver.auth.units.loggedout.LoggedOutPresenter.View$lambda$5$lambda$4(LoggedOutPresenter.java:48)
at cab.app.driver.auth.units.loggedout.ui.LoggedOutScreenKt$LoggedOutScreen$2$1$1.invoke$lambda$2$lambda$1(LoggedOutScreen.kt:113)
at androidxpose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke-k-4lQ0M(Clickable.kt:167)
at androidxpose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke(Clickable.kt:156)
at androidxpose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1.invokeSuspend(TapGestureDetector.kt:255)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:179)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:168)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
at androidxpose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:566)
at androidxpose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:456)
at androidxpose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:469)
at androidxpose.ui.node.BackwardsCompatNode.onPointerEvent-H0pRuoY(BackwardsCompatNode.kt:374)
at androidxpose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:314)
at androidxpose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
at androidxpose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
at androidxpose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
at androidxpose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
at androidxpose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
at androidxpose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:183)
at androidxpose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:102)
at androidxpose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:98)
at androidxpose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1361)
at androidxpose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1307)
at androidxpose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1246)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3316)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:1116)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1971)
at android.app.Activity.dispatchTouchEvent(Activity.java:4388)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:70)
at io.sentry.android.core.internal.gestures.WindowCallbackAdapter.dispatchTouchEvent(WindowCallbackAdapter.java:39)
at io.sentry.android.core.internal.gestures.SentryWindowCallback.dispatchTouchEvent(SentryWindowCallback.java:64)
at curtains.internal.WindowCallbackWrapper$dispatchTouchEvent$dispatch$1.invoke(WindowCallbackWrapper.kt:58)
at curtains.internal.WindowCallbackWrapper$dispatchTouchEvent$dispatch$1.invoke(WindowCallbackWrapper.kt:52)
at curtains.OnTouchEventListener$DefaultImpls.intercept(Listeners.kt:96)
at cab.app.driver.utils.ClickTrace$install$1$1$1.intercept(ClickTrace.kt:47)
at curtains.internal.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.kt:65)
at io.sentry.android.core.internal.gestures.WindowCallbackAdapter.dispatchTouchEvent(WindowCallbackAdapter.java:39)
at io.sentry.android.core.internal.gestures.SentryWindowCallback.dispatchTouchEvent(SentryWindowCallback.java:64)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:1074)
at android.view.View.dispatchPointerEvent(View.java:15803)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:8153)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:7877)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7213)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7270)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7236)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:7434)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7244)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:7491)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7217)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7270)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7236)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7244)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7217)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:10788)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:10676)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:10632)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:10926)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:285)
at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
at android.os.MessageQueue.next(MessageQueue.java:335)
at android.os.Looper.loopOnce(Looper.java:186)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8762)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
these are some snips of my code, where the issue happened:
val otpResponse: MutOTPResponse?
get() {
return (sharedPreferencesManager.get(OTP_RESPONSE) as? MutOTPResponse)
}
@Nullable
public <T> T get(String key)
{
T value = null;
if (containsKey(key))
{
value = Hawk.get(key);
}
return value;
}
data class MutOTPResponse(
@SerializedName("fake_name_1") val fakeName1: String,
@SerializedName("fake_name_2") val fakeName2: String?,
@SerializedName("fake_name_3") val fakeName3: String?,
@SerializedName("fake_name_4") val fakeName4: String?,
@SerializedName("fake_name_5") val fakeName5: Int?
) : NetworkResponseModel()
open class NetworkResponseModel {
lateinit var rawResponse: String
}
Actual Behavior:
The application crashes with a java.lang.StackOverflowError
. The stack trace indicates a recursive call to com.hivemq.client.internal.mqtt.datatypes.MqttUtf8StringImpl.toString()
, suggesting an issue with how Hawk is handling the underlying data. The fact that Mqtt
classes are involved is very suspicious, and may indicate a bug in how Hawk interacts with certain data types, or perhaps that the data being stored is somehow related to MQTT.
Important Considerations
On which android versions do you have this issue? Android 10, 11, 13, 14
On which phones do you have this issue?
- Samsung(Galaxy M21, Galaxy S9, Galaxy A30s)
- Xiaomi(Redmi Note 13, Poco X4 Pro 5G, Redmi Note 13 Pro+ 5G)
- Huawei(Mate 20 Pro)
Which hawk version are you using? : 2.0.1
Does this issue happen always or is it flaky? : This bug is not reproducible for me, but in the latest version of project, it is happening for 10% of users(about 100 people).
Is the data you are trying to save it huge or small? small