Skip to content

[LokiJS] Fix unsafeResetDatabase failing while an autosave is in progress - #1980

Open
joker-777 wants to merge 1 commit into
Nozbe:masterfrom
kenhub:fix/loki-reset-while-saving
Open

joker-777 wants to merge 1 commit into
Nozbe:masterfrom
kenhub:fix/loki-reset-while-saving

Conversation

@joker-777

@joker-777 joker-777 commented Oct 31, 2026 •

Copy link
Copy Markdown

Problem

unsafeResetDatabase() on the LokiJS adapter calls deleteDatabase(loki), which does loki.close(() => loki.deleteDatabase(...)).

close() only waits for a save if Loki is dirty. An autosave clears the dirty flags when it starts (in getLokiCopy), so while one is in flight Loki looks clean. close() then emits 'close' synchronously (Loki's listeners are synchronous), and IncrementalIndexedDBAdapter.deleteDatabase throws Error while deleting database - another operation is already in progress because operationInProgress is still true. The throw comes out of loki.close() inside the Promise executor, so the reset rejects.

Fix

After close(), wait for Loki's throttled save queue to drain (throttledSaveDrain) before calling deleteDatabase. Two small guards:

  • throttledSaveDrain calls its callback twice when throttledSaves is disabled (a lokijs bug: missing return), so the drain is skipped in that case.
  • The delete now runs in an async callback, where a throw would no longer reject the promise and would leave the reset hanging. It's wrapped in try/catch so it still rejects.

Note: when a save is pending, Loki's drain runs one more save before calling back. That save finishes before the delete starts, so it's harmless.

Test

New Jest test in src/adapters/lokijs/test.js. A fake incremental persistence adapter passed through _testLokiAdapter mimics IncrementalIndexedDBAdapter: it throws on save/delete while another operation is in progress and can keep a save in flight. The test starts a save, calls unsafeResetDatabase(), checks that nothing is deleted while the save runs, then finishes the save and checks that the reset completes and the data is gone. Without the fix it fails with "another operation is already in progress".

  • jest src/adapters/lokijs src/adapters/__tests__: 140 passed
  • eslint, tslint and flow focus-check on the changed file: clean

Independent of #1979 (persistence error reporting); the two touch lokiExtensions.js in different places and merge cleanly in either order.

🤖 Generated with Claude Code

unsafeResetDatabase() closes Loki and then deletes the database. close()
only waits for a save when Loki is dirty, but an autosave clears the dirty
flags as soon as it starts. If one was still running, close() emitted
'close' synchronously and IncrementalIndexedDBAdapter.deleteDatabase threw
"another operation is already in progress", rejecting the reset.

Drain Loki's throttled save queue after close() and before deleting.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@StasDoskalenko

Copy link
Copy Markdown

Hi @joker-777, thank you, nice find!

I maintain NitromelonDB, a maintained fork of WatermelonDB (New Architecture, Nitro Modules). It still ships the LokiJS adapter with the same deleteDatabase code, so this race exists there too, and a PR against our repo would be very welcome (src/adapters/lokijs/worker/lokiExtensions.ts). Our fork was rewritten in TypeScript (strict mode) to reduce the chance of bugs like this one slipping through, so I think the community would really benefit if you opened your PRs against it too.

Also possibly worth a look: on the web, our SQLiteAdapter now runs SQLite compiled to WASM (wa-sqlite) in a web worker, stored in IndexedDB. It's the same import and adapter as on native. There's no autosave queue to race with, since writes are real SQLite transactions, so it might be a better long-term option than LokiJS. More details are in the wa-sqlite adapter docs. One caveat: existing LokiJS data in the browser is not migrated automatically.

If you don't have the time or would rather not, no worries at all, I'm happy to port it myself. Just let me know. Thanks a lot!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants