OperationError when calling `read()` on web
I'm getting the following error when calling read() on web, only if the key exists in storage. It works fine if the key does not exist. Calling containsKey() returns the correct value and does not produce this error.
Error: OperationError
at Object.createErrorWithStack (http://localhost:5000/dart_sdk.js:5080:12)
at Function._throw (http://localhost:5000/dart_sdk.js:20337:18)
at Function.throwWithStackTrace (http://localhost:5000/dart_sdk.js:20334:18)
at async._AsyncCallbackEntry.new.callback (http://localhost:5000/dart_sdk.js:40851:18)
at Object._microtaskLoop (http://localhost:5000/dart_sdk.js:40708:13)
at _startMicrotaskLoop (http://localhost:5000/dart_sdk.js:40714:13)
at http://localhost:5000/dart_sdk.js:36191:9
This seems to be triggered from invoking the callback function in the following block:
static _scheduleImmediateWithPromise(callback) {
dart.addAsyncCallback();
dart.global.Promise.resolve(null).then(() => {
dart.removeAsyncCallback();
callback();
});
}
I'm running Chromium 99.0.4844.82 on Arch Linux
Any thoughts on what this could be caused by?
NB: OperationError seems to be a DomException constant.
I'm encountering the same error on macOS.
+1
+1 I also have this on web
From what I can see the error is in
flutter_secure_storage_web.dart:152
Future<String?> _decryptValue(
String? cypherText,
Map<String, String> options,
) async {
if (cypherText == null) {
return null;
}
final parts = cypherText.split(".");
final iv = base64Decode(parts[0]);
final algorithm = _getAlgorithm(iv);
final decryptionKey = await _getEncryptionKey(algorithm, options);
final value = base64Decode(parts[1]);
final decryptedContent = await js_util.promiseToFuture<ByteBuffer>(
crypto.decrypt(
_getAlgorithm(iv),
decryptionKey,
Uint8List.fromList(value),
),
);
final plainText = utf8.decode(decryptedContent.asUint8List());
return plainText;
}
in this block
final decryptedContent = await js_util.promiseToFuture<ByteBuffer>(
crypto.decrypt(
_getAlgorithm(iv),
decryptionKey,
Uint8List.fromList(value),
),
);
Might this be relevant?
https://stackoverflow.com/questions/68160151/how-to-fix-this-operationerror-error-when-decrypting-data-with-crypto-api
Here is the relevant part of the stack trace

I get this error as well. Have any of you found out why, or a fix?
This is not happening on all read()s in my case. I't is one of the keys that constantly fail. I have tried using dummy values and the same values for the two keys, but it is always only one of them that fails.
Also, how do you get a thorough stack trace like that? All I see in my logs when doing catch(e,s) and printing those are the OperationError
I used the webserver command
flutter run -d web-server
And then I got a thorough stack trace. I think this is a issue with the way the decrypting is done, and I myself do not have much experience with encryption and know that it is easy to make mistakes if not done properly.
I had the same issue on macOS using the Web version.
My mistake was not using async / await properly - after adding "await" to ALL read / write functions, everything was working fine.
Hope that helps!
Thanks for both tips! Managed to get it working by creating a class for my fields and save them as JSON strings. When doing a read on that field then I had no issue 🤷 Will see if I bump into it again
@momrak were you storing a JWT by any chance,? We are. I wonder if the decryption fails for certain characters. Thanks for the tip!
@momrak were you storing a JWT by any chance,? We are. I wonder if the decryption fails for certain characters. Thanks for the tip!
JWTs are Base64url encoded and separated by '.'s, so they should not contain any characters other than [A-Za-z0-9-_.]. It would be very strange if this character set is unsuitable for storage.
@duck-dev-go Yes, this was the case for an access token JWT. But I tried changing to simple strings as well just to see if that helped, but I still got then problem when doing that. Hope combining them might work for you as well :)
I can confirm that storing it as json works. I wonder why. Maybe you can't store multiple things? Anyway thanks @momrak !
I think what is happening is that when you want to store multiple values it overrides the encryption key. So that is why it works as json. Because the name of the encryption key will stay the same in localstorage. So I don't think this is a bug, but docs would help.
Faced this issue too. For some reason, it occurs only when I run the app on localhost.
I found a workaround for this issue. Make sure you're not writing to the storage concurrently. Just await for each operation.
Consider having this function.
Future<void> _writeString(String key, String value) async {
const storage = FlutterSecureStorage();
await storage.write(key: key, value: value);
}
Calling it like this will produce read errors further on
_writeString("key1", "data");
_writeString("key2", "some other data");
but awaiting for them will work just fine
await _writeString("key1", "data");
await _writeString("key2", "some other data");
#427 Hi guys, it looks like you are using the package for the web. Can you please explain some facets to me, I have to implement a web app and times are tight. You would do me a great pleasure if you give me examples and maybe explain the bare minimum. I'm finding it wrong with the documentation because it doesn't exist.
@shroff , @pedro371 , @SlavisDEV , @duck-dev-go , @momrak
PS: Sorry for the tags but I have delivery times, Thanks in advance
thank you apetroaeiandrei!
i added the synchronized package https://pub.dev/packages/synchronized, then wrapped my writes with:
await _lock.synchronized(() async {
await secureStorage!.write(key: key, value: value);
});
operationerror issues gone!
Encoding object as json works, thx @momrak