{"record":{"id":"e983d76454f9899f","repo":"microg/GmsCore","slug":"upgrades-not-supported","errorCode":null,"errorMessage":"Upgrades not supported","messagePattern":"Upgrades not supported","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetDatabase.kt","lineNumber":128,"sourceCode":"        val sqLiteStatement = db.compileStatement(\"DELETE FROM $TABLE_RECENTS WHERE $FIELD_TIMESTAMP + ? < ?\")\n        sqLiteStatement.bindLong(1, timeout.toLong())\n        sqLiteStatement.bindLong(2, System.currentTimeMillis())\n        rows += sqLiteStatement.executeUpdateDelete()\n\n        if (rows != 0) Log.d(TAG, \"Cleared $rows old request(s)\")\n    }\n\n    fun clearAllRequests() {\n        val db = writableDatabase\n        db.execSQL(\"DELETE FROM $TABLE_RECENTS\")\n    }\n\n    override fun onCreate(db: SQLiteDatabase) {\n        db.execSQL(CREATE_TABLE_RECENTS)\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {\n        throw IllegalStateException(\"Upgrades not supported\")\n    }\n\n    companion object {\n        private val TAG = SafetyNetDatabase::class.java.simpleName\n        private const val DB_NAME = \"snet.db\"\n        private const val DB_VERSION = 1\n        private const val CREATE_TABLE_RECENTS = \"CREATE TABLE recents (\" +\n                \"id INTEGER PRIMARY KEY AUTOINCREMENT ,\" +\n                \"request_type TEXT,\" +\n                \"package_name TEXT,\" +\n                \"nonce TEXT,\" +\n                \"timestamp INTEGER,\" +\n                \"result_status_code INTEGER DEFAULT NULL,\" +\n                \"result_status_msg TEXT DEFAULT NULL,\" +\n                \"result_data TEXT DEFAULT NULL)\"\n        private const val TABLE_RECENTS = \"recents\"\n        private const val FIELD_ID = \"id\"\n        private const val FIELD_REQUEST_TYPE = \"request_type\"","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-safetynet/core/src/main/kotlin/org/microg/gms/safetynet/SafetyNetDatabase.kt#L110-L146","documentation":"SafetyNetDatabase.onUpgrade() deliberately throws IllegalStateException(\"Upgrades not supported\") because the database schema (DB_VERSION = 1) has never had a migration path. If SQLite detects an existing snet.db file with an old version number (or a corrupt version), the framework calls onUpgrade, which immediately fails instead of migrating.","triggerScenarios":"Opening the SafetyNet recents database when the on-disk snet.db has a version lower than the current DB_VERSION, or a schema/pragma mismatch causing SQLiteOpenHelper to attempt an upgrade path.","commonSituations":"Downgrading the app or microG after a future schema bump, a corrupt/partially-written database reporting a wrong version, or copying a database file from a different version of the app.","solutions":["Delete the old snet.db file (clear app data or remove databases/snet.db) so onCreate() recreates it fresh","Catch the IllegalStateException and fall back to deleting and reopening the database","Restore a matching app/microG version so the on-disk DB version matches DB_VERSION","If maintaining the code, implement a real onUpgrade migration instead of throwing"],"exampleFix":"// before\ntry { db = helper.writableDatabase } // throws on old schema\n// after\ntry {\n    db = helper.writableDatabase\n} catch (e: IllegalStateException) {\n    context.deleteDatabase(\"snet.db\")\n    db = helper.writableDatabase // recreated via onCreate\n}","handlingStrategy":"try-catch","validationCode":"val v = SQLiteDatabase.openDatabase(dbPath, null, OPEN_READONLY).version; if (v < CURRENT_DB_VERSION) context.deleteDatabase(\"snet.db\")","typeGuard":null,"tryCatchPattern":"try { helper.writableDatabase } catch (e: IllegalStateException) { context.deleteDatabase(\"snet.db\"); helper.writableDatabase }","preventionTips":["Treat snet.db as disposable (recents cache)","Never downgrade the app across schema bumps","Catch upgrade failures and recreate the DB"],"tags":["kotlin","safetynet","sqlite","database-migration"],"backgroundTag":"invalid-state-transition","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}