This issue was originally created by @JAStanton as facebook/react-native#12529.
### Description
When reading values that are too large using AsyncStorage on Android I run into this error:
I wrote a large value with AsyncStorage and later tried to read it, but it crashed.
BaseError: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at e (/node_modules/react-native/Libraries/Storage/AsyncStorage.js:423:22)
at None (/node_modules/react-native/Libraries/Storage/AsyncStorage.js:416:71)
at map ([native code])
at errors (/node_modules/react-native/Libraries/Storage/AsyncStorage.js:416:51)
at slicedToArray (/node_modules/react-native/Libraries/Storage/AsyncStorage.js:54:33)
It looks like on iOS we write to disk when the value is above a threshold and on Android we write to sqllite always.
let x = 'x';
while (x.length <= 3194304) {
x = `${x}${x}`;
}
await AsyncStorage.setItem('@@GARBAGE@@', x); // works
const garbage = await AsyncStorage.getItem('@@GARBAGE@@'); // throws
In order for me to fix this I'll need to re-write AsyncStorage to write to disk instead of writing to sql. https://github.com/mvayngrib/react-native-safe-async-storage <--- this guys has the right idea but his code is super old and broken.
Workaround:
async getSafeItem(key) {
return new Promise((resolve, reject) => {
if (!key) {
reject('Invalid key');
}
AsyncStorage.getItem(createKey(key)).then((value) => {
resolve(value);
}, () => {// Couldn't read row 0, col 0 from CursorWindow
resolve(null); // Force not to break
});
});
}
Additional Information
@Krizzu why API: AsyncStorage label was removed if it is related?
@juliopiubello Because this whole module is about AS. Since everything is related I just remove redundant labels
@juliopiubello were you able to solve it? I'm having the same issue
According to this comment on SO, CursorWindow size limit is 2MB per row (I couldn't find official docs saying that but let's assume it for now).
Repro steps by OP gives us a 4194304 length string. According to ECMAScript specification, each character takes 2 bytes of memory, so whole is something around 8.38 MB.
This is way over the limit of CursorWindow, hence the crash.
Now, to work around this:
Try not to store your whole object as a single entity (by stringifying objects) - divide it into smaller pieces, then store in at different AS keys
Write a helper that will save large data into filesystem, instead to AS
thanks.
2MB seems to be correct. CursorWindow's default constructor just pulls the number from the internal configuration.
@Krizzu Would it make sense to have a warning here in dev mode to make people more aware of the limitation?
@tido64 You mean like checking for string length before calling Native Module? We could do it, I can imagine those JSON strings parsed all the time :)
If you need more help with this particular issue, please do let us know.
https://github.com/react-native-community/async-storage/pull/99
will this update help me to over the limit of CursorWindow?