Conversation
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
|
Important Indent Zero has shut down and no longer reviews pull requests.
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. |
|
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 insidenode:electron/js2c/node_init, with no application frames above it — this is Node/Electron failing todlopen()the nativebetter_sqlite3.nodebinary.database-store.tsimportsbetter-sqlite3as a top-level, unguardedimport 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 genericwindow.onerror/uncaughtExceptionhandlers (app-env.ts), which just report it to Sentry — it never goes throughopenDatabase()'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:better-sqlite3import type-only, and lazilyrequire()the module insideopenDatabase()via a newrequireSqlite3()helper that retries up to 3 times with a 1s delay between attempts.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
import type+typeof import('better-sqlite3')) type-checks cleanly against the project's pinned@types/better-sqlite3@^7.6.3in an isolated TypeScript check (couldn't run the full project'stsc/eslintin this sandbox — nonode_modulesinstalled).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