drift
drift copied to clipboard
No modification allowed Error
In my Flutter Web export, I somehow ended up in a state that no longer allows me to access the database. Unfortunately I don't know how to reproduce this.
I get the following error message:
**NoModificationAllowedError: No modification allowed** main.dart.js:63922:17 ===== asynchronous gap =========================== main.dart.js:63922:17 main.dart.js 16597:38 StackTrace_current main.dart.js:63922:17 main.dart.js 111079:131 request$1$2$requestId main.dart.js:63922:17 main.dart.js 111084:19 request$1$1 main.dart.js:63922:17 main.dart.js 111002:102 ensureOpen$body$_RemoteQueryExecutor.<fn> main.dart.js:63922:17 main.dart.js 13632:17 _wrapJsFunctionForAsync.<fn> main.dart.js:63922:17 main.dart.js 94958:12 call$2 main.dart.js:63922:17 main.dart.js 13596:20 _asyncStartSync main.dart.js:63922:17 main.dart.js 111011:16 ensureOpen$body$_RemoteQueryExecutor main.dart.js:63922:17 main.dart.js 110986:19 ensureOpen$1 main.dart.js:63922:17 main.dart.js 114516:17 call$1 main.dart.js:63922:17 main.dart.js 14212:18 _rootRunUnary main.dart.js:63922:17 main.dart.js 247136:16 <fn> main.dart.js:63922:17 main.dart.js 97440:39 runUnary$2$2 main.dart.js:63922:17 main.dart.js 95952:51 call$0 main.dart.js:63922:17 main.dart.js 13949:93 _Future__propagateToListeners main.dart.js:63922:17 main.dart.js 95816:9 _completeWithValue$1 main.dart.js:63922:17 main.dart.js 95894:18 call$0 main.dart.js:63922:17 main.dart.js 14202:16 _rootRun main.dart.js:63922:17 main.dart.js 247132:16 <fn> main.dart.js:63922:17 main.dart.js 97435:39 run$1$1 main.dart.js:63922:17 main.dart.js 97371:14 runGuarded$1 main.dart.js:63922:17 main.dart.js 97565:25 call$0 main.dart.js:63922:17 main.dart.js 14010:24 _microtaskLoop main.dart.js:63922:17 main.dart.js 14016:11 _startMicrotaskLoop main.dart.js:63922:17 main.dart.js 94837:9 call$1 main.dart.js:63922:17 main.dart.js 13559:9 MutationCallback*_AsyncRun__initializeScheduleImmediate main.dart.js:63922:17 main.dart.js 256829:110 <fn> main.dart.js:63922:17 main.dart.js 116:21 lazyFinal.<fn> main.dart.js:63922:17 main.dart.js 14030:13 _scheduleAsyncCallback main.dart.js:63922:17 main.dart.js 14255:9 _rootScheduleMicrotask main.dart.js:63922:17 main.dart.js 97734:9 scheduleMicrotask$1 main.dart.js:63922:17 main.dart.js 95832:18 _asyncCompleteWithValue$1 main.dart.js:63922:17 main.dart.js 95828:12 _asyncComplete$1 main.dart.js:63922:17 main.dart.js 94923:23 complete$1 main.dart.js:63922:17 main.dart.js 13604:17 _asyncReturn main.dart.js:63922:17 main.dart.js 20137:24 bootstrapEngine.<fn> main.dart.js:63922:17 main.dart.js 13632:17 _wrapJsFunctionForAsync.<fn> main.dart.js:63922:17 main.dart.js 94958:12 call$2 main.dart.js:63922:17 main.dart.js 13596:20 _asyncStartSync main.dart.js:63922:17 main.dart.js 20140:16 bootstrapEngine main.dart.js:63922:17 main.dart.js 63900:38 main.<fn> main.dart.js:63922:17 main.dart.js 13632:17 _wrapJsFunctionForAsync.<fn> main.dart.js:63922:17 main.dart.js 94958:12 call$2 main.dart.js:63922:17 main.dart.js 13596:20 _asyncStartSync main.dart.js:63922:17 main.dart.js 63907:16 main main.dart.js:63922:17 main.dart.js 257504:15 <fn> main.dart.js:63922:17 main.dart.js 257485:15 <fn> main.dart.js:63922:17 main.dart.js 257498:5 dartProgram main.dart.js:63922:17 main.dart.js 257507:3 <fn> main.dart.js:63922:17 <empty string> 2 main.dart.js:63922:17
This error is currently occurring in Firefox and I see that WasmStorageImplementation.opfsShared is being used. Does anyone have any idea what this could be and how I can at least delete the database from Firefox so that it is recreated? Other browsers work fine.
No idea on what could have caused this yet. Docs say that NoModificationAllowedError may be thrown by the browser then accessing the same OPFS file multiple times. Can you check whether there's anything in your app that may cause two different database instances to be around without first closing the first one?
If opening the same database two times at the same time is indeed the problem here, deleting databases won't fix this. One way to delete all files for a website is to go to about:settings, then "Privacy & Security", then "Manage data..." under "Cookies and Website Data". You can entirely clear all content Firefox has set for a given domain there.
Deleting OPFS files is tricky since they're not listed in Firefox Devtools, but I think pasting this snippet to the console should work if no database instance is currently open:
(async () => {
let opfsRoot = await navigator.storage.getDirectory();
let deleted = 0;
for await (const [key, value] of opfsRoot.entries()) {
await opfsRoot.removeEntry(key, { recursive: true });
deleted++;
}
console.log(`Done, deleted ${deleted} entries!`);
})()
Thanks for the quick answer!
If i run the script in Firefox i receive:
Promise { <state>: "pending" } <state>: "rejected" <reason>: DOMException: No modification allowed code: 7 columnNumber: 0 data: null filename: "" lineNumber: 0 message: "No modification allowed" name: "NoModificationAllowedError" result: 2152923143 stack: "" <prototype>: DOMExceptionPrototype { name: Getter, message: Getter, INDEX_SIZE_ERR: 1, … } <prototype>: Promise.prototype { … }
When i run in in another Browser it deletes the db as expected and after a reload the db is recreated and works as expected.
Firefox runs with WasmStorageImplementation.opfsShared and my other Browsers with WasmStorageImplementation.opfsLocks. On another machine the App works fine in Firefox.
If the No modification allowed exception happens, your database is currently open somewhere. You could try serving a version of your app once where you never open the database just to check and delete OPFS files, but the problem will likely come back afterwards.
With opfsLocks, each tab uses its own database instance and briefly opens the file only when it needs to read or write it. opsShared is a more efficient mode where we use a shared worker that keeps the database files open all the time and serves requests coming in from all tabs. Since a shared worker is used, it should be impossible to reach that state.
To help me debug this, could you look at about:debugging#workers and see if there are multiple shared workers for your application active? You mentioned that you don't have a way to reproduce this, does the problem not go away after closing your app and re-opening it? Or after deleting data for your app in Firefox settings?
I managed to delete the db with the script before the app opens the db.
After a reload i noticed, that the app now runs with WasmStorageImplementation.sharedIndexedDb and i receive:
NotFoundError: IDBDatabase.transaction: 'files' is not a known object store name
error.
Im stuck in this state until i delte the indexed db via dev tools and reload.
After reload im in WasmStorageImplementation.opfsShared mode again and everything works as expected!
The app now works fine from the affected browser. unfortunately I don't know how to reproduce the initial problem. When I had the initial problem, neither reloading nor restarting the browser helped.
If i have an open tab with the app the abount:debugging#workers shows this:
If i close the tab the three entries disappear.
I seem to be getting this issue, it happens in Firefox when I rapidly open/close my application tab. I now have a drift_worker.js that exists even with all tabs of my application closed and when I open a new tab to my app it now spawns a second drift_worker.js.
That worker is unable to access the database (probably because the existing drift_worker already has a lock on it), and so my application fails to run.
Is there a way to either
- re-connect to the existing shared worker? OR
- kill the running shared worker?
I found that restarting firefox fixes the issue but that is pretty annoying when I have multiple windows open and would have to do a lot of work to restart my whole browser.
I now have a drift_worker.js that exists even with all tabs of my application closed and when I open a new tab to my app it now spawns a second drift_worker.js
This behavior sounds very unexpected to me and might be a browser bug. If you inspect the existing worker and pause script execution, is it doing anything (e.g. hitting some kind of infinite loop)? I wonder if Firefox decided to spawn a second worker because the first one became unresponsive. After all, shared workers are generally supposed to be... well, shared.
This happened to me like 5 times yesterday. Today I am trying to reproduce and can't seem to get the exact situation that triggered it.
If I can get it to reproduce I will debug the worker and see what it is up to.
So when clicking the "inspect" button on the stuck worker its just completely blank:
And now if I open my app I see two drift_worker.js
The second one I can see normal debugging and console output but it is getting a "No modification allowed" error (probably because of the zombie worker still there)
According to your documentation:
Downsides of COOP and COEP
While these headers are required for the origin-private FileSystem Access API and bring a security benefit, there are some known problems:
These headers are incompatible with some other packages opening popups, such as the ones used for Google Auth.
I am using google auth and I see the issue the most when using the google auth. However, the auth succeeds, its just the drift worker that seems to die.
I will try without the headers and see what happens
EDIT: although, without the headers, I won't have a shared worker... So I guess that solves the bug too.
Just an update, I still regularly see this issue. I am happy to help debug this if you need anything from me.
@lologarithm If you have a way to reproduce this somewhat consistently, I'd be happy to take a look at that.
EDIT: although, without the headers, I won't have a shared worker
On Firefox, we should use OPFS in a shared worker even without these headers.