Skip to content

Room migration crash — GlobalSearchEntity missing chartId column on v1 → v2 upgrade #164

@sande11

Description

@sande11

Summary

Users who had the app installed before v2 and updated to it crash immediately on launch with IllegalStateException. The app remains permanently broken for them on every subsequent launch.


IllegalStateException: Migration didn't properly handle: GlobalSearchEntity
Expected: columns = { chapterId, chartId, fileName, isChart, searchTitle, subChapter, subChapterId, textInBody }
Found:    columns = { chapterId, fileName, isChart, searchTitle, subChapter, subChapterId, textInBody }

Root cause

Users who installed the app more than 18 months ago (before chartId was added to GlobalSearchEntity) and only just updated to v2.0 are affected. MIGRATION_1_2 was written only to add the Contact table and did not account for the older GlobalSearchEntity schema that predates it — leaving these long-dormant installs with a database missing chartId. Room validates the schema after migration, finds the mismatch, and crashes permanently on every launch.

Fix

Step 1 — Bump DB version to 3
In Database.kt:

@database(version = 3, ...)
Step 2 — Fix MIGRATION_1_2 and add MIGRATION_2_3
In AppModule.kt:

private val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL(/* Contact table CREATE — unchanged */)
        // Recreate FTS table to include chartId (use exact SQL from schema export)
        db.execSQL("DROP TABLE IF EXISTS `GlobalSearchEntity`")
        db.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `GlobalSearchEntity` USING fts4(...)")
    }
}

private val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(db: SupportSQLiteDatabase) {
        // Unblocks users already stuck on broken v2
        db.execSQL("DROP TABLE IF EXISTS `GlobalSearchEntity`")
        db.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `GlobalSearchEntity` USING fts4(...)")
    }
}

Register both:

.addMigrations(MIGRATION_1_2, MIGRATION_2_3)

What is not at risk

Notes, bookmarks, and contacts are untouched — only the search index is dropped and recreated
GlobalSearchEntity is always reseeded on app init so users will have full search after the first launch

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions