Skip to content

Retry loading better-sqlite3 native module before failing database open - #2846

Open
bengotow wants to merge 1 commit into
masterfrom
claude/awesome-ritchie-rbdbm2
Open

bengotow wants to merge 1 commit into
masterfrom
claude/awesome-ritchie-rbdbm2

Conversation

@bengotow

@bengotow bengotow commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes MAILSPRING-CLIENT-9: Error: The paging file is too small for this operation to complete. (11 users, 62 occurrences over ~4 months on Windows).

What I observed: the Sentry stack trace shows the error originating from process.func [as dlopen] deep inside node:electron/js2c/node_init, with no application frames above it — this is Node/Electron failing to dlopen() the native better_sqlite3.node binary. database-store.ts imports better-sqlite3 as a top-level, unguarded import Sqlite3 from 'better-sqlite3', so if the native module fails to load (here, because Windows reports the paging file/virtual memory is too small to satisfy the mapping), the failure is an uncaught exception with no relation to the actual database file. It's only caught by the app's generic window.onerror / uncaughtException handlers (app-env.ts), which just report it to Sentry — it never goes through openDatabase()'s existing error handling, and the app is left in a broken, unexplained state.

Windows can transiently report insufficient paging-file/commit-charge room for a native module's memory mapping when the system is under memory pressure at that exact instant (multiple Electron/mailsync processes, other apps, etc.), so simply retrying the load after a short delay is a well-known, effective mitigation — the OS often finds room a moment later.

What I changed in app/src/flux/stores/database-store.ts:

  • Made the better-sqlite3 import type-only, and lazily require() the module inside openDatabase() via a new requireSqlite3() helper that retries up to 3 times with a 1s delay between attempts.
  • If the module still fails to load after retries, report the error to Sentry and show the user an actionable dialog explaining their system may be low on virtual memory, rather than silently leaving the app hung.
  • Deliberately did not route this failure through the existing handleUnrecoverableDatabaseError (which triggers a full local database reset + resync) — that's the wrong response here, since the database file itself is fine; only the native driver failed to load.

Test plan

  • Verified the lazy-require pattern (import type + typeof import('better-sqlite3')) type-checks cleanly against the project's pinned @types/better-sqlite3@^7.6.3 in an isolated TypeScript check (couldn't run the full project's tsc/eslint in this sandbox — no node_modules installed).
  • Exercise on Windows (or by temporarily forcing require('better-sqlite3') to throw) to confirm the retry/dialog path behaves as expected.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DzBiH9WKXBG4BU6QGUxqTM


Generated by Claude Code

Loading the native better-sqlite3 binary can fail transiently with
"The paging file is too small for this operation to complete" under
Windows virtual memory pressure (MAILSPRING-CLIENT-9). The require()
was previously a top-level import, so this failure was an unhandled
exception unrelated to the database file, yet it was indistinguishable
from a corrupt database and left the app stuck without explanation.

Retry the module load a few times before giving up, and if it still
fails, report a clear, actionable error instead of treating it as an
unrecoverable database error (which would wipe and resync local data
for a problem that has nothing to do with the database itself).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DzBiH9WKXBG4BU6QGUxqTM
@indent-staging

indent-staging Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Important

Indent Zero has shut down and no longer reviews pull requests.
To get this pull request reviewed by Indent instead:

  1. Sign up for Indent
  2. Install Indent on your repositories
  3. Turn on code review
  4. Comment @indent on this pull request

Step 4 is only needed for pull requests that were already open when you switched. After that, Indent reviews new pull requests on its own.

To stop this notice, turn PR reviews off in Indent Zero.

@indent

indent Bot commented Sep 2, 2026

Copy link
Copy Markdown
PR Summary

Fixes MAILSPRING-CLIENT-9: on Windows, loading the native better_sqlite3.node binary can transiently fail under virtual-memory pressure ("The paging file is too small for this operation to complete"). Because the module was a top-level import, that failure crashed during module load and was never routed through openDatabase()'s handling. This change defers and retries the native-module load so the transient case recovers, and gives the user an actionable dialog instead of wiping/resyncing the local database when the load genuinely can't complete.

  • app/src/flux/stores/database-store.ts: change import Sqlite3 from 'better-sqlite3' to a type-only import; lazily require() the module inside openDatabase().
  • Add requireSqlite3(), which retries the load up to 3 times with a 1s delay between attempts before giving up.
  • Add handleUnavailableSqliteModule(), which reports the error to Sentry and shows a localized dialog explaining the system may be low on virtual memory, rather than routing through handleUnrecoverableDatabaseError (which would delete and rebuild the DB).

Issues

No issues found.

CI Checks

All CI checks passed on eba1dad.

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