Realm-java: Index out of bounds in migration transformation

Created on 11 Nov 2019  路  10Comments  路  Source: realm/realm-java

Goal

Run transformation in a migration for all elements. If a linking object (Bar) is found, I want to set a the string from Bar.bbb on the DynamicRealmObject (Foo.aaa) and if not, I want to remove the Foo-object.

schema.get("Foo")?.apply {
    addField("aaa", String::class.java)

    transform { dro ->
        dro.linkingObjects("Bar", "foo")
            ?.firstOrNull()
            ?.apply {
                dro.setString("aaa", getString("bbb"))
            }
            ?: dro.deleteFromRealm()
    }
}

Actual Results

This works fine on a few test devices I could test but crashlytics reports many crashes for end users.
I get 2 crashes:

Fatal Exception: java.lang.IllegalStateException: Row index out of range
Exception backtrace:
<backtrace not supported on this platform>
       at io.realm.internal.CheckedRow.nativeSetString(CheckedRow.java)
       at io.realm.internal.UncheckedRow.setString(UncheckedRow.java:234)
       at io.realm.DynamicRealmObject.setString(DynamicRealmObject.java:689)
       at de.loewen.lcsmobile.migration.MigrateToVersion23Kt$migrateToVersion23$1$1.apply(MigrateToVersion23Kt.java:36)
       at io.realm.MutableRealmObjectSchema.transform(MutableRealmObjectSchema.java:288)
       at de.loewen.lcsmobile.migration.MigrateToVersion23Kt.migrateToVersion23(MigrateToVersion23Kt.java:26)
       at de.loewen.lcsmobile.migration.RealmMigrationManager.migrate(RealmMigrationManager.java:50)

and

Fatal Exception: java.lang.ArrayIndexOutOfBoundsException: rowIndex > available rows: 54 > 53
       at io.realm.internal.Table.nativeMoveLastOver(Table.java)
       at io.realm.internal.Table.moveLastOver(Table.java:330)
       at io.realm.RealmObject.deleteFromRealm(RealmObject.java:115)
       at io.realm.RealmObject.deleteFromRealm(RealmObject.java:87)
       at de.loewen.lcsmobile.migration.MigrateToVersion23Kt$migrateToVersion23$1$1.apply(MigrateToVersion23Kt.java:46)
       at io.realm.MutableRealmObjectSchema.transform(MutableRealmObjectSchema.java:288)
       at de.loewen.lcsmobile.migration.MigrateToVersion23Kt.migrateToVersion23(MigrateToVersion23Kt.java:26)
       at de.loewen.lcsmobile.migration.RealmMigrationManager.migrate(RealmMigrationManager.java:50)

Steps & Code to Reproduce

This seems to happen everytime the user opens the app (and a migration is needed). As said, I cannot reproduce it myself because it's working on my devices.

Version of Realm and tooling

Realm version(s): 6.0.0

Realm Sync feature enabled: No

Android Studio version: 3.6 Beta 3

Android Build Tools version: 29.0.2

Gradle version: 5.6.4

Which Android version and device(s): 8.0.0 (Galaxy S7) crashes on the user; I've tested an S7 with 8.0.0 as well which worked. Also tested Android 10, 9, 8, 7, 6, 5 - all working.

O-Community T-Bug

Most helpful comment

Fixed in 6.1.0

All 10 comments

Out of curiosity, is encryption enabled?

Out of curiosity, is encryption enabled?

No (I saw the fix for it in 6.0.1)

Interesting problem you have, but overall the trick seems to be that transform is applied to all elements within that given object schema through a regular iterator, rather than over a snapshot collection.

The solution would be to save the "candidates for deletion" into a Set<? extends RealmObject> and delete the objects only after the transform {} is actually done.

Currently I don't have a Realm-based project open so I don't see the actual generated implementation for the transform { call, but this is my guess.

So the problem is that removing an entry of the still-running iterator causes those 2 errors? Sounds plausible. I'll add your "candidates for deletion" approach. Thanks!

Seems like this fix worked. No more crashes. Closing.

Could this issue be reopened?
This doesn't feel intuitive at all since deleteFromRealm is available in the obj in transform, I'd expect it to work.

Hmm, so the solution would be to remove DynamicRealmObject.deleteFromRealm()? This might be a good idea to prevent such errors like mine.

Doesn't mean you shouldn't be able to delete items using the DynamicRealm API.

The trick is that transform should iterate backwards.

I guess we didn't account for people deleting objects in the transform method. We should fix this by either making a snapshot or iterating backward. It doesn't look like we guarantee any specific order of the elements being returned, so that should work.

But yes, this looks like a bug on our end.

Fixed in 6.1.0

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aschrijver picture aschrijver  路  3Comments

wyvern610 picture wyvern610  路  3Comments

wezley98 picture wezley98  路  3Comments

mithrann picture mithrann  路  3Comments

AAChartModel picture AAChartModel  路  3Comments