'Could not encrypt/decrypt the value for SecureStore' error on android app
Minimal reproducible example
https://snack.expo.dev/@simranjits11/error-with-securestorage
Summary
Context
When trying to get item using await SecureStore.getItemAsync('mobile'). It throws an error saying Could not encrypt/decrypt the value for SecureStore. The error is very device specific and happens occasionally.
- Message: Error: Could not encrypt/decrypt the value for SecureStore .
- SDK: 47.0.12
- Device: OnePlus 8T (Android 13)
Stack Trace
Could not encrypt/decrypt the value for SecureStore
at .construct([native code]:0:0) at .construct([native code]:0:0)
at .p(index.android.bundle:50:360)
at .s(index.android.bundle:48:363)
at .construct([native code]:0:0)
at .<unknown>(index.android.bundle:395:595)
at .h(index.android.bundle:395:731)
Environment
expo-env-info 1.0.5 environment info: System: OS: macOS 13.3.1 Shell: 5.9 - /bin/zsh Binaries: Node: 18.14.2 - ~/.nvm/versions/node/v18.14.2/bin/node Yarn: 1.22.19 - /opt/homebrew/bin/yarn npm: 9.6.7 - ~/Documents/Projects/realmagic/node_modules/.bin/npm Watchman: 2023.02.20.00 - /opt/homebrew/bin/watchman Managers: CocoaPods: 1.11.3 - /Users/simranjitsingh/.rbenv/shims/pod SDKs: iOS SDK: Platforms: DriverKit 22.4, iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4 IDEs: Android Studio: 2020.3 AI-203.7717.56.2031.7678000 Xcode: 14.3/14E222b - /usr/bin/xcodebuild npmPackages: react: 18.1.0 => 18.1.0 react-dom: 18.1.0 => 18.1.0 npmGlobalPackages: eas-cli: 3.15.0 expo-cli: 6.3.2 Expo Workflow: managed
Got same error on OnePlus 10T 5G (CPH2415)
Thank you for filing this issue! This comment acknowledges we believe this may be a bug and there’s enough information to investigate it. However, we can’t promise any sort of timeline for resolution. We prioritize issues based on severity, breadth of impact, and alignment with our roadmap. If you’d like to help move it more quickly, you can continue to investigate it more deeply and/or you can open a pull request that fixes the cause.
Same error on a series of devices like SM-A127F, Pixel 7, SM-F926B, Note 9P, SM-S918B, SM-M135F, etc... with Expo SDK 49 and RN 0.72.1
@behenate is currently working on the migration to the new modules api so he will look into this also
@nicolascavallin You managed to reproduce the issue on a lot of devices, do you have any specific steps for reproduction?
@behenate I didn't reproduce the error in those devices, I've just extracted the models from Sentry.
We have no specific implementation, just like @Simranjits11 provided repro. We are storing a JSON with 3 keys parsed as a string.
In so many other Android devices everything is working.
I don't know how can I help
Are you saving the keys with requireAuthentication set to true?
@behenate I have noticed that this issue mostly comes up if i install a new build (apk) without clearing the app data (by going to app info in device settings) of the previously installed build.
If i clear the app data and then uninstall the previous build before installing the new build, then i don't see the issue. I haven't tested a lot of devices for this behaviour so not sure if this is consistent across all devices, but found this interesting. It might help you pin point the issue.
Seems like the previously present app data/cache is causing the issue in the new build in some device models
Are you saving the keys with
requireAuthenticationset totrue?
No
I can also repro this issue in SM-T220.
I'm getting: Could not encrypt/decrypt the value for SecureStore in Sentry on these devices.
I have this configuration:
const secureOptions = {
requireAuthentication: false,
authenticationPrompt: 'Authenticate to Verify Your Identity',
keychainAccessible: SecureStore.ALWAYS_THIS_DEVICE_ONLY,
};
const saveAccessToken = async (value: string) => {
await SecureStore.setItemAsync(
'accessToken',
value,
secureOptions
);
// Do something with the token
}
@behenate Yes and no. We save two keys in the secure store. One with auth, one without. But both happen at the same time. First without auth, second with.
Is there any update or a resolution to this issue? We're seeing this issue on Android devices. At a minimum, Samsung Galaxy S23 and Pixel 7a. No specific secure options used, just the default config. On expo-secure-store version 12.1.1, but I'm unsure if it's happening on other versions. Android only issue. Does not happen on iOS.
@behenate any updates? Our users keep complaining that our app signs them off and it's related to this bug 😢
I've tried to reproduce the issue on similar devices to the ones mentioned above (Galaxy S22 and Pixel 6), but couldn't reproduce it. Using @Simranjits11's suggestion also didn't produce the issue. Is it possible for any of you to share the native Android logs, which are created when the issue occurs? There should be a warning logged under "ExpoSecureStore" tag.
@behenate I'm not sure if this is useful, but the only thing I can extract from Sentry is the stack trace:
Error: secure-session/set-session | Could not encrypt the value for SecureStore
at ?anon_0_(/Users/vagrant/git/src/shared/modules/authentication/ui/hooks/useSecureAuth.ts:165:22)
at throw(native)
at asyncGeneratorStep(/Users/vagrant/git/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
at _throw(/Users/vagrant/git/node_modules/@babel/runtime/helpers/asyncToGenerator.js:25:57)
at tryCallOne(/Users/vagrant/git/node_modules/promise/setimmediate/core.js:36:3)
at anonymous(/Users/vagrant/git/node_modules/promise/setimmediate/core.js:123:34)
at apply(native)
at anonymous(/Users/vagrant/git/node_modules/react-native/Libraries/Core/Timers/JSTimers.js:247:35)
at _callTimer(/Users/vagrant/git/node_modules/react-native/Libraries/Core/Timers/JSTimers.js:113:15)
at _callReactNativeMicrotasksPass(/Users/vagrant/git/node_modules/react-native/Libraries/Core/Timers/JSTimers.js:161:41)
at callReactNativeMicrotasks(/Users/vagrant/git/node_modules/react-native/Libraries/Core/Timers/JSTimers.js:415:12)
at __callReactNativeMicrotasks(/Users/vagrant/git/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:392:42)
at anonymous(/Users/vagrant/git/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:132:39)
at __guard(/Users/vagrant/git/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:367:7)
at flushedQueue(/Users/vagrant/git/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:131:18)
Same issue found after upgrading to "expo-secure-store": "~12.1.1" and expo SDK 48 on android device
@behenate
Error Could not encrypt/decrypt the value for SecureStore
[native code] construct
[native code] construct
node_modules/@babel/runtime/helpers/construct.js:16:26 _construct
node_modules/@babel/runtime/helpers/wrapNativeSuper.js:17:23 Wrapper
[native code] construct
node_modules/expo-modules-core/build/errors/CodedError.js:6:13
node_modules/expo-modules-core/build/errors/CodedError.js:10:8 CodedError
Thread 2 - main - (RUNNABLE)
at com.facebook.systrace.Systrace.endSection(Systrace.java:55)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1083)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:175)
at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:85)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1410)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1420)
at android.view.Choreographer.doCallbacks(Choreographer.java:1047)
at android.view.ChoreographerExtImpl.checkScrollOptSceneEnable(ChoreographerExtImpl.java:442)
at android.view.Choreographer.doFrame(Choreographer.java:918)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1395)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:240)
at android.os.Looper.loop(Looper.java:351)
at android.app.ActivityThread.main(ActivityThread.java:8416)
at java.lang.reflect.Method.invoke(Method.java:-2)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
Thread 1684 - Signal Catcher - (WAITING)
at unknown method(unknown file)
Thread 1685 - HeapTaskDaemon - (WAITING)
at unknown method(unknown file)
Thread 1686 - Jit thread pool worker thread 0 - (RUNNABLE)
at unknown method(unknown file)
Thread 1687 - ReferenceQueueDaemon - (WAITING)
at java.lang.Object.wait(Object.java:-2)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:232)
at java.lang.Daemons$Daemon.run(Daemons.java:140)
at java.lang.Thread.run(Thread.java:1012)
Thread 1688 - FinalizerDaemon - (WAITING)
at java.lang.Object.wait(Object.java:-2)
at java.lang.Object.wait(Object.java:442)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:203)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:224)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:300)
at java.lang.Daemons$Daemon.run(Daemons.java:140)
at java.lang.Thread.run(Thread.java:1012)
Thread 1689 - FinalizerWatchdogDaemon - (WAITING)
at java.lang.Object.wait(Object.java:-2)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:385)
at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:365)
at java.lang.Daemons$Daemon.run(Daemons.java:140)
at java.lang.Thread.run(Thread.java:1012)
Thread 1690 - binder:12584_1 - (RUNNABLE)
at unknown method(unknown file)
Thread 1691 - binder:12584_2 - (RUNNABLE)
at unknown method(unknown file)
Thread 1692 - Profile Saver - (RUNNABLE)
at unknown method(unknown file)
Thread 1693 - Bugsnag IO thread - (WAITING)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:433)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1063)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1123)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Thread 1695 - pool-2-thread-1 - (TIMED_WAITING)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1188)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:905)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1063)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1123)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Thread 1696 - Bugsnag Default thread - (TIMED_WAITING)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:458)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1062)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1123)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Thread 1697 - process reaper - (TIMED_WAITING)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:463)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:361)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:939)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1062)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1123)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Thread 1698 - bugsnag-anr-collector - (RUNNABLE)
at android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
at android.os.MessageQueue.next(MessageQueue.java:349)
at android.os.Looper.loopOnce(Looper.java:186)
at android.os.Looper.loop(Looper.java:351)
at android.os.HandlerThread.run(HandlerThread.java:67)
Thread 1699 - Bugsnag Error thread - (WAITING)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:433)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1063)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1123)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Thread 1700 - Bugsnag Session thread - (WAITING)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-2)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2081)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:433)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1063)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1123)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Thread 1701 - ConnectivityThread - (RUNNABLE)
at android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
at android.os.MessageQueue.next(MessageQueue.java:349)
at android.os.Looper.loopOnce(Looper.java:186)
at android.os.Looper.loop(Looper.java:351)
at android.os.HandlerThread.run(HandlerThread.java:67)
Thread 1702 - AppCenter.Looper - (RUNNABLE)
at android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
at android.os.MessageQueue.next(MessageQueue.java:349)
at android.os.Looper.loopOnce(Looper.java:186)
at android.os.Looper.loop(Looper.java:351)
at android.os.HandlerThread.run(HandlerThread.java:67)
Thread 1704 - queued-work-looper - (RUNNABLE)
at android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
at android.os.MessageQueue.next(MessageQueue.java:349)
at android.os.Looper.loopOnce(Looper.java:186)
at android.os.Looper.loop(Looper.java:351)
at android.os.HandlerThread.run(HandlerThread.java:67)
Thread 1705 - oplus.app.bg - (RUNNABLE)
at android.os.MessageQueue.nativePollOnce(MessageQueue.java:-2)
at android.os.MessageQueue.next(MessageQueue.java:349)
at android.os.Looper.loopOnce(Looper.java:186)
at android.os.Looper.loop(Looper.java:351)
at android.os.HandlerThread.run(HandlerThread.java:67)
Thread 1706 - UIMonitorThread - (TIMED_WAITING)
at java.lang.Thread.sleep(Thread.java:-2)
at java.lang.Thread.sleep(Thread.java:450)
at java.lang.Thread.sleep(Thread.java:355)
at android.os.SystemClock.sleep(SystemClock…
Same issue here after upgrading expo to: 49.0.3 and expo-secure-store to: 12.3.1. It seems like the issue goes away when restarting the app but returns randomly. (Device: Samsung Galaxy Z Flip 5)
Hi, We are also experiencing this issue, thanks for looking into it is there a version where the issue happens less frequently or a workaround? I guess an ETA for the fix can not be provided yet, correct?
@DavidRG13 Hi, sorry I can't provide any ETA, because we couldn't reproduce the issue, any instructions on a reliable way to reproduce the issue would be really helpful.
We are working on an update to expo-secure-store it doesn't contain a specific fix for the issue but improves the error logging so it might give us some insights into the issue after we release it.
This issue appears in SM-A146P/DSN and SM-A307FN/DS.
As pointed out by @behenate, the issue disappears if you delete data and cache in the app's Settings.
Has anyone tried to downgrade expo-secure-store?
I have not yet tried to downgrade. What has worked for me is to create a function that tries 5 times before failing as a workaround.
I can confirm the same issue on Android. Exact the same error and fixed by deleting data and cache in the app's settings as @behenate described. So if a user uninstalls and then installs again it will always throw the error and force the user to go to app settings to clear data.
Ok, so apparently it is normal behavior not to delete Secure Storage and also It is normal not being able to decrypt old data after reinstalling. The solution is to return null in a try/catch and save new data inside the same key. You can always save new data inside the same key but you cannot read old data from an old installation.
Also experiencing this issue.
Using expo ~48.0.0, expo-secure-store ~12.1.1 and react-native 0.71.3.
Device: OnePlus 5t, still on Android 10.
Experiencing this error when (manually) installing a new APK of our app. I believe this may be device-related: this issue seems to be a lot more prevalent on the device I test with.
Also experiencing this issue.
Using
expo ~48.0.0,expo-secure-store ~12.1.1andreact-native 0.71.3.Device: OnePlus 5t, still on Android 10.
Experiencing this error when (manually) installing a new APK of our app. I believe this may be device-related: this issue seems to be a lot more prevalent on the device I test with.
As I explained in the comment just before,this is not considered an issue. This is normal behavior. Expo cannot control nor delete secure storage once app is uninstalled. If you had an old version/apk and used secure storage expo cannot and will not delete it when you uninstall the app. Later on if you try to read to the same key/value the data is encrypted from the old version so you cannot read it. The solution is tu just return null inside a try/catch and write again inside the same key/value. Works perfectly.
Could you at least throw or return a specific, typed error, so we know that's what happened? Because otherwise we're seeing this thousands of time on Sentry, and I have to investigate manually to make sure it's “the expected behavior” and not some other issue in that try/catch block.
Also experiencing this issue.
Using
expo ~48.0.0,expo-secure-store ~12.1.1andreact-native 0.71.3.Device: OnePlus 5t, still on Android 10.
Experiencing this error when (manually) installing a new APK of our app. I believe this may be device-related: this issue seems to be a lot more prevalent on the device I test with.
As I explained in the comment just before,this is not considered an issue. This is normal behavior. Expo cannot control nor delete secure storage once app is uninstalled. If you had an old version/apk and used secure storage expo cannot and will not delete it when you uninstall the app. Later on if you try to read to the same key/value the data is encrypted from the old version so you cannot read it. The solution is tu just return null inside a try/catch and write again inside the same key/value. Works perfectly.
This behavior also occurs after an app has been updated (iOS).
Could you at least throw or return a specific, typed error, so we know that's what happened? Because otherwise we're seeing this thousands of time on Sentry, and I have to investigate manually to make sure it's “the expected behavior” and not some other issue in that
try/catchblock.
I'm just telling you what I found after some research. I don't work neither maintain any Expo package. That said, if there is any error in the catch section you should return null since the value for the given key couldn't be found, doesn't matter the error. Of course would be great to know the error and of course have a typed error, but that won't change how you should handle it.
Getting the same error on a series of devices like SM-A225F, SM-A307FN and Redmi Note 9 Pro.
Currently trying the try/catch fix suggested