fix: swallow SQLITE_BUSY when setting WAL mode to prevent startup crash (#508) #510

Merged
guettlibot merged 4 commits from refs/pull/510/head into main 2026-06-06 22:32:15 +00:00
guettlibot commented 2026-06-06 21:37:25 +00:00 (Migrated from codeberg.org)

Summary

  • A WorkManager background task can hold the database open when the foreground app starts. PRAGMA journal_mode = WAL on the second connection then fails with SQLITE_BUSY_SNAPSHOT (extended code 261, primary code 5), crashing before the UI renders.
  • Move PRAGMA busy_timeout = 5000 before the WAL pragma so SQLite auto-retries plain SQLITE_BUSY for up to 5 s.
  • Extract the setup logic into a named _setupPragmas function and catch SqliteException with resultCode == 5 (covers both SQLITE_BUSY and SQLITE_BUSY_SNAPSHOT). SQLITE_BUSY_SNAPSHOT only occurs when the DB is already in WAL mode, so the pragma is effectively a no-op and it is safe to continue.

Closes #508

Test plan

  • New regression test in test/unit/migration_test.dart (WAL setup (#508)) opens a second connection while a read transaction holds a WAL snapshot and verifies setupPragmasForTesting does not throw.
  • All existing migration tests still pass.
  • flutter test test/unit/background_sync_test.dart test/unit/database_path_test.dart passes.

🤖 Generated with Claude Code

## Summary - A WorkManager background task can hold the database open when the foreground app starts. `PRAGMA journal_mode = WAL` on the second connection then fails with `SQLITE_BUSY_SNAPSHOT` (extended code 261, primary code 5), crashing before the UI renders. - Move `PRAGMA busy_timeout = 5000` before the WAL pragma so SQLite auto-retries plain `SQLITE_BUSY` for up to 5 s. - Extract the setup logic into a named `_setupPragmas` function and catch `SqliteException` with `resultCode == 5` (covers both `SQLITE_BUSY` and `SQLITE_BUSY_SNAPSHOT`). `SQLITE_BUSY_SNAPSHOT` only occurs when the DB is already in WAL mode, so the pragma is effectively a no-op and it is safe to continue. Closes #508 ## Test plan - [x] New regression test in `test/unit/migration_test.dart` (`WAL setup (#508)`) opens a second connection while a read transaction holds a WAL snapshot and verifies `setupPragmasForTesting` does not throw. - [x] All existing migration tests still pass. - [x] `flutter test test/unit/background_sync_test.dart test/unit/database_path_test.dart` passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.