Skip to content

fix: recover from corrupt SQLite database files on startup#1077

Merged
perber merged 3 commits into
mainfrom
fix/sqlite-corrup-db-recovery
May 30, 2026
Merged

fix: recover from corrupt SQLite database files on startup#1077
perber merged 3 commits into
mainfrom
fix/sqlite-corrup-db-recovery

Conversation

@perber
Copy link
Copy Markdown
Owner

@perber perber commented May 30, 2026

LeafWiki failed to start after an upgrade if a previous run left a stale SQLite journal file (search.db-journal), causing disk I/O error 3338.

On startup, all four derived SQLite stores (search, links, tags, properties) now detect genuine I/O and corruption errors (SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_NOTADB), delete the database and any sidecar files, and retry initialization once. Since these stores are always rebuilt from the Markdown files on disk, the delete is safe.

Transient errors (SQLITE_BUSY, SQLITE_LOCKED) and resource errors (SQLITE_IOERR_NOMEM) are not treated as recoverable — they are returned immediately without touching the database files.

Shared helpers (IsSQLiteRecoverableError, RemoveSQLiteFiles) live in internal/core/shared/sqliteutil to avoid coupling non-database packages to the SQLite module. The auth stores (users.db, sessions.db) are intentionally excluded from auto-recovery as they hold primary data.

Fixes #1072

LeafWiki failed to start after an upgrade if a previous run left a stale SQLite journal file (search.db-journal), causing disk I/O error 3338.

On startup, all four derived SQLite stores (search, links, tags,
properties) now detect genuine I/O and corruption errors
(SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_NOTADB), delete the database and
any sidecar files, and retry initialization once. Since these stores are
always rebuilt from the Markdown files on disk, the delete is safe.

Transient errors (SQLITE_BUSY, SQLITE_LOCKED) and resource errors
(SQLITE_IOERR_NOMEM) are not treated as recoverable — they are returned
immediately without touching the database files.

Shared helpers (IsSQLiteRecoverableError, RemoveSQLiteFiles) live in internal/core/shared/sqliteutil to avoid coupling non-database packages to the SQLite module. The auth stores (users.db, sessions.db) are intentionally excluded from auto-recovery as they hold primary data.

Fixes #1072
Copilot AI review requested due to automatic review settings May 30, 2026 17:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Recovers from corrupt or stale SQLite database files for the four derived stores (search, links, tags, properties) on startup by detecting a narrow set of recoverable SQLite errors, deleting the DB plus sidecar files (-journal, -wal, -shm), and retrying initialization once. This addresses the upgrade failure in #1072 where a stale search.db-journal produced "disk I/O error (3338)" and prevented startup. The auth stores (users.db, sessions.db) are intentionally left untouched because they hold primary data.

Changes:

  • Adds internal/core/shared/sqliteutil with IsSQLiteRecoverableError (matches SQLITE_IOERR=10, SQLITE_CORRUPT=11, SQLITE_NOTADB=26; explicitly excludes SQLITE_IOERR_NOMEM=3082) and RemoveSQLiteFiles.
  • Wraps ensureSchema failures in NewSQLiteIndex, NewLinksStore, NewTagsStore, and NewPropertiesStore with a one-shot delete-and-retry recovery path.
  • Misc cleanup in internal/search/sqlite_index.go (removes a stray log.Printf per-row in Search, drops unused "log" import).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/core/shared/sqliteutil/sqlite.go New shared helpers: classify recoverable SQLite errors and remove DB + sidecar files.
internal/search/sqlite_index.go Adds recovery around ensureSchema; removes per-row log.Printf and unused import; stray extra blank line.
internal/links/links_store.go Adds recovery around ensureSchema, resetting s.db and re-Connect-ing on retry.
internal/tags/tags_store.go Adds recovery: closes db, removes files, reopens and re-runs ensureSchema.
internal/properties/properties_store.go Adds recovery: closes db, removes files, reopens and re-runs ensureSchema.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/core/shared/sqliteutil/sqlite.go
Comment thread internal/search/sqlite_index.go
Copilot finished work on behalf of perber May 30, 2026 17:47
@perber perber merged commit 32ffe81 into main May 30, 2026
8 checks passed
@perber perber deleted the fix/sqlite-corrup-db-recovery branch May 30, 2026 18:02
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.

Failure to upgrade LeafWiki to version v.0.10.0 from v.0.9.2 on Windows 11

3 participants