java.lang.IllegalStateException: Cannot create asynchronous query while in a write transaction in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 310
Goal
Avoid crashes.
Expected Results
Crashes do not happen. Transactions completes successful without crashes. Also I want to know what kind of code can lead to this crash.
Actual Results
Error. StackTrace:
java.lang.IllegalStateException: Cannot create asynchronous query while in a write transaction in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 310
at io.realm.internal.Collection.nativeStartListening(Native Method)
at io.realm.internal.Collection.addListener(Collection.java:490)
at io.realm.internal.Collection.addListener(Collection.java:497)
at ...
Steps & Code to Reproduce
I do not know how to reproduce it. I haven't got anything helpful after searching all the issues and in stackoverflow.com. And I also searched the crash message Cannot create asynchronous query while in a write transaction in realm source code but found nothing. It's not a new issue and I first found this crash about one month ago. I found some similar problems in I-OS Realm, but there is no information about the solution https://github.com/realm/realm-cocoa/issues/4539 https://github.com/realm/realm-cocoa/issues/4231 https://stackoverflow.com/questions/42012222/realm-why-are-notification-blocks-triggered-when-a-write-transaction-begins
Code Sample
I've read the doc and cannot find what's wrong with my code. I know how to avoid common problems like nested transactions. But this one is killing me. Our application (en.techops.brief) uses several threads and asynchronous transactions. The problem periodically occurs in different parts of the code, here are two cases and a stacktrace:
Case 1: Useq StackTrace: https://gist.github.com/andrey7mel/e121d0e856bb20d536d970a314bdf3b0 Realm 3.3.0
05-25 18:25:02.659 15486-15486/ru.techops.brief.debug E/REALM_JNI: jni: ThrowingException 8, Cannot create asynchronous query while in a write transaction in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 310, .
05-25 18:25:02.659 15486-15486/ru.techops.brief.debug E/REALM_JNI: Exception has been thrown: Cannot create asynchronous query while in a write transaction in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 310
05-25 18:25:02.666 15486-15486/ru.techops.brief.debug E/ChatPresenter.l()[351]: Error while getting chat events:
java.lang.IllegalStateException: Cannot create asynchronous query while in a write transaction in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 310
at io.realm.internal.Collection.nativeStartListening(Native Method)
at io.realm.internal.Collection.addListener(Collection.java:490)
at io.realm.internal.Collection.addListener(Collection.java:497)
at io.realm.RealmResults.addChangeListener(RealmResults.java:171)
at io.realm.rx.RealmObservableFactory$6.call(RealmObservableFactory.java:153)
at io.realm.rx.RealmObservableFactory$6.call(RealmObservableFactory.java:137)
at rx.Observable.unsafeSubscribe(Observable.java:10256)
at rx.internal.operators.OnSubscribeFilter.call(OnSubscribeFilter.java:45)
at rx.internal.operators.OnSubscribeFilter.call(OnSubscribeFilter.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:10256)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.Observable.unsafeSubscribe(Observable.java:10256)
at rx.internal.operators.OperatorSwitch$SwitchSubscriber.onNext(OperatorSwitch.java:155)
at rx.internal.operators.OperatorSwitch$SwitchSubscriber.onNext(OperatorSwitch.java:77)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:77)
at rx.internal.operators.OperatorCast$CastSubscriber.onNext(OperatorCast.java:69)
at rx.internal.operators.OnSubscribeFilter$FilterSubscriber.onNext(OnSubscribeFilter.java:76)
at rx.internal.operators.OnSubscribeFilter$FilterSubscriber.onNext(OnSubscribeFilter.java:76)
at io.realm.rx.RealmObservableFactory$10$1.onChange(RealmObservableFactory.java:293)
at io.realm.rx.RealmObservableFactory$10$1.onChange(RealmObservableFactory.java:289)
at io.realm.ProxyState$RealmChangeListenerWrapper.onChange(ProxyState.java:46)
at io.realm.internal.OsObject$ObjectObserverPair.onChange(OsObject.java:69)
at io.realm.internal.OsObject$Callback.onCalled(OsObject.java:88)
at io.realm.internal.OsObject$Callback.onCalled(OsObject.java:73)
at io.realm.internal.ObserverPairList.foreach(ObserverPairList.java:108)
at io.realm.internal.OsObject.notifyChangeListeners(OsObject.java:236)
at io.realm.internal.SharedRealm.nativeBeginTransaction(Native Method)
at io.realm.internal.SharedRealm.beginTransaction(SharedRealm.java:262)
at io.realm.BaseRealm.beginTransaction(BaseRealm.java:348)
at io.realm.BaseRealm.beginTransaction(BaseRealm.java:343)
at io.realm.Realm.beginTransaction(Realm.java:131)
at io.realm.Realm.executeTransaction(Realm.java:1441)
at ru.techops.brief.model.database.DataBase.executeTransaction(DataBase.java:1720)
at ru.techops.brief.model.database.DataBase.lambda$null$1(DataBase.java:149)
at ru.techops.brief.model.database.DataBase$$Lambda$160.call(Unknown Source)
at rx.internal.operators.OnSubscribeCreate.call(OnSubscribeCreate.java:72)
at rx.internal.operators.OnSubscribeCreate.call(OnSubscribeCreate.java:32)
at rx.Observable.unsafeSubscribe(Observable.java:10256)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:224)
at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6688)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Code transaction:
// ru.techops.brief.model.database.DataBase.lambda$null$1(DataBase.java:149)
saveUseqSubject
.onBackpressureLatest()
.concatMap(useq -> Observable.create(emitter -> {
executeTransaction(realm -> {
Useq useqObj = realm.where(Useq.class).findFirst();
if (useqObj == null) {
useqObj = new Useq();
}
useqObj.setUseq(useq);
realm.insertOrUpdate(useqObj);
emitter.onNext(useq);
});
}, Emitter.BackpressureMode.BUFFER))
.subscribe(useq1 -> Timber.v("Saved to database Useq=" + useq1),
e -> Timber.e(e, "Error while saving useq to Realm"));
//ru.techops.brief.model.database.DataBase.executeTransaction(DataBase.java:1720)
private void executeTransaction(Realm.Transaction transaction) {
try (Realm realm = getRealm()) {
realm.executeTransaction(transaction);
}
}
Case 2: SaveEvents Stacktrace: https://gist.github.com/andrey7mel/10e6b54e741d99d08bd2f6174cece094 Realm 3.1.4
Non-fatal Exception: java.lang.IllegalStateException: Cannot create asynchronous query while in a write transaction in /home/cc/repo/realm/release/realm/realm-library/src/main/cpp/io_realm_internal_Collection.cpp line 310
at io.realm.internal.Collection.nativeStartListening(Collection.java)
at io.realm.internal.Collection.addListener(Collection.java:490)
at io.realm.internal.Collection.addListener(Collection.java:497)
at io.realm.RealmResults.addChangeListener(RealmResults.java:136)
at io.realm.rx.RealmObservableFactory$6.call(RealmObservableFactory.java:153)
at io.realm.rx.RealmObservableFactory$6.call(RealmObservableFactory.java:137)
at rx.Observable.unsafeSubscribe(Observable.java:10346)
at rx.internal.operators.OnSubscribeFilter.call(OnSubscribeFilter.java:45)
at rx.internal.operators.OnSubscribeFilter.call(OnSubscribeFilter.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:10346)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.Observable.unsafeSubscribe(Observable.java:10346)
at rx.internal.operators.OperatorSwitch$SwitchSubscriber.onNext(OperatorSwitch.java:155)
at rx.internal.operators.OperatorSwitch$SwitchSubscriber.onNext(OperatorSwitch.java:77)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:77)
at rx.internal.operators.OperatorCast$CastSubscriber.onNext(OperatorCast.java:69)
at rx.internal.operators.OnSubscribeFilter$FilterSubscriber.onNext(OnSubscribeFilter.java:76)
at rx.internal.operators.OnSubscribeFilter$FilterSubscriber.onNext(OnSubscribeFilter.java:76)
at io.realm.rx.RealmObservableFactory$10$1.onChange(RealmObservableFactory.java:293)
at io.realm.rx.RealmObservableFactory$10$1.onChange(RealmObservableFactory.java:289)
at io.realm.ProxyState$RealmChangeListenerWrapper.onChange(ProxyState.java:46)
at io.realm.internal.OsObject$ObjectObserverPair.onChange(OsObject.java:67)
at io.realm.internal.OsObject$Callback.onCalled(OsObject.java:86)
at io.realm.internal.OsObject$Callback.onCalled(OsObject.java:71)
at io.realm.internal.ObserverPairList.foreach(ObserverPairList.java:108)
at io.realm.internal.OsObject.notifyChangeListeners(OsObject.java:149)
at io.realm.internal.SharedRealm.nativeBeginTransaction(SharedRealm.java)
at io.realm.internal.SharedRealm.beginTransaction(SharedRealm.java:246)
at io.realm.BaseRealm.beginTransaction(BaseRealm.java:309)
at io.realm.Realm.beginTransaction(Realm.java:128)
at io.realm.Realm.executeTransaction(Realm.java:1408)
at ru.techops.brief.model.database.DataBase.executeTransaction(DataBase.java:1729)
at ru.techops.brief.model.database.DataBase.saveEventsSync(DataBase.java:636)
at ru.techops.brief.model.Model.lambda$saveEventsSync$85(Model.java:888)
at ru.techops.brief.model.Model$$Lambda$70.call(Unknown Source)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:69)
at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276)
at rx.internal.producers.ProducerArbiter.setProducer(ProducerArbiter.java:126)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapInnerSubscriber.setProducer(OnSubscribeConcatMap.java:329)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.setProducer(OnSubscribeMap.java:102)
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138)
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129)
at rx.Observable.unsafeSubscribe(Observable.java:10346)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.Observable.unsafeSubscribe(Observable.java:10346)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.innerCompleted(OnSubscribeConcatMap.java:209)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapInnerSubscriber.onCompleted(OnSubscribeConcatMap.java:345)
at rx.observers.SerializedObserver.onCompleted(SerializedObserver.java:176)
at rx.observers.SerializedSubscriber.onCompleted(SerializedSubscriber.java:64)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:246)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.innerCompleted(OnSubscribeConcatMap.java:209)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapInnerSubscriber.onCompleted(OnSubscribeConcatMap.java:345)
at rx.observers.SerializedObserver.onCompleted(SerializedObserver.java:176)
at rx.observers.SerializedSubscriber.onCompleted(SerializedSubscriber.java:64)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:246)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.innerCompleted(OnSubscribeConcatMap.java:209)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapInnerSubscriber.onCompleted(OnSubscribeConcatMap.java:345)
at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:656)
at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:568)
at rx.internal.operators.OperatorMerge$MergeSubscriber.onCompleted(OperatorMerge.java:281)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.onCompleted(OnSubscribeMap.java:97)
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onCompleted(OperatorOnErrorResumeNextViaFunction.java:101)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:281)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:216)
at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5896)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:948)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:809)
Code:
// ru.techops.brief.model.Model.lambda$saveEventsSync$85(Model.java:888)
public Completable saveEventsSync(List<WsUpdateEventNew> updates) {
List<Event> events = new ArrayList<>();
for (WsUpdateEventNew update : updates) {
events.add(update.getEvent());
}
return Observable.from(events)
.concatMap(event -> {
Observable<Object> res = Observable.empty();
User sender = dataBase.getUserSyncFromRealm(event.getSenderId());
if (sender == null) {
res = res.concatWith(getUserInfoFromServer(event.getSenderId()));
}
Peer fwdSenderPeer = event.getFwdSenderPeer();
if (fwdSenderPeer != null) {
User fwdSender = dataBase.getUserSyncFromRealm(fwdSenderPeer.getPeerId());
if (fwdSender == null) {
res = res.concatWith(getUserInfoFromServer(fwdSenderPeer.getPeerId()));
}
}
Peer peer = event.getPeer();
Const.NotifyMode notifyMode = dataBase.getPeerNotifyMode(peer);
if (notifyMode == Const.NotifyMode.NOTIFY_UNKNOWN) {
switch (peer.getType()) {
case PeerType.USER:
res = res.concatWith(getUserInfoFromServer(event.getPeer().getPeerId()));
break;
case PeerType.GROUP:
res = res.concatWith(getGroupInfoFromServer(event.getPeer().getPeerId()));
break;
}
}
if (event.getReplyToId() != 0) {
res = res.concatWith(loadEventIfNeed(event.getPeer(), event.getReplyToId()).ignoreElements());
}
return res;
})
.concatWith(Observable.just(events)
.map(e -> {
// (Model:888)
dataBase.saveEventsSync(e);
return e;
}))
.toCompletable();
}
//ru.techops.brief.model.database.DataBase.saveEventsSync(DataBase.java:636)
@WorkerThread
public void saveEventsSync(List<Event> events) {
executeTransaction(realm -> {
for (Event event : events) {
saveEventToRealm(event, realm);
}
});
}
// ru.techops.brief.model.database.DataBase.executeTransaction(DataBase.java:1729)
private void executeTransaction(Realm.Transaction transaction) {
try (Realm realm = getRealm()) {
realm.executeTransaction(transaction);
}
}
Version of Realm and tooling
Realm version(s): 3.1.4 - 3.3.0
Realm sync feature enabled: no
Android Studio version: 2.3.2
Which Android version and device: Android 5 - 6 - 7, many devices

Well the error technically means that you have synchronous Realm write on the UI thread, and at some point it tries to call asObservable in a switchMap operation on an async query results, and it breaks.
But I'm not sure exactly where it happens, except that beginTransaction wants to call the change listeners, and that's when the crash is triggered.
I am not a Realm person, by the way, so this is by no means the official support response.
This looks weird to me. I've asked some of our ObjectStore experts to have a look. Unfortunately, we have holidays in the US, Denmark, and the UK, on Monday, so this may not get attention until mid next week.
Previously it just silently converted async query to sync query, it didn't throw exception :D
It is a known restriction from Object Store that Results.addChangeListener() cannot be called in the transaction now. This needs to be documented in the javadoc.
@beeender Adding that restriction to findAllAsync() would probably be more appropriate?
@andrey7mel Can you also post the saveEventToRealm(event, realm); method in your code above?
@cmelchior due to the nature of how Object Store running the queries, even findAll() will be put into background thread if it is possible. That means calling findAll().addChangeListener() inside a transaction is not allowed as well.
@cmelchior
private void saveEventToRealm(Event event, Realm bgRealm) {
User sender = bgRealm.where(User.class).equalTo("id", event.getSenderId()).findFirst();
if (sender != null) {
event.setSender(sender);
}
if (event.getFwdSenderPeer() != null) {
User fwdUser = bgRealm.where(User.class).equalTo("id", event.getFwdSenderPeer().getPeerId()).findFirst();
if (fwdUser != null) {
event.setFwdSender(fwdUser);
}
}
ServiceAction action = event.getAction();
if (action != null && action.getUserId() != 0) {
User actionUser = bgRealm.where(User.class).equalTo("id", action.getUserId()).findFirst();
if (actionUser != null) {
action.setUser(actionUser);
event.setAction(action);
}
}
if (event.getReplyToId() != 0) {
setReplyEvent(event, bgRealm);
}
event.setState(Event.EventState.SENT);
FileBrief file = event.getFile();
if (file != null && event.getFile() != null) {
file.setId(event.getFile().getId());
}
Event eventRealm = bgRealm.copyToRealmOrUpdate(event);
Chat chat = bgRealm.where(Chat.class)
.equalTo("peer.uniquePeerId", event.getPeer().getUniquePeerId())
.findFirst();
if (chat != null) {
if (event.getSenderId() != getSelfUserId() && event.getId() > chat.getReadEventId()) {
int unreadCount = chat.getUnreadCountSafe();
chat.setUnreadCount(unreadCount + 1);
}
Timber.d("Chat " + chat.getChatName() + " , set last event - " + event.getText());
chat.setLastEvent(eventRealm);
} else {
Timber.i("Chat == null in saveEvent => create new chat");
if (event.getPeer().getType().equals(PeerType.USER)) {
User user = bgRealm.where(User.class).equalTo("id", event.getPeer().getPeerId()).findFirst();
if (user != null) {
chat = new Chat(event.getPeer(), eventRealm, user);
bgRealm.insertOrUpdate(chat);
} else {
Timber.e("Chat == null, user == null, can't create Chat");
}
} else {
Group group = bgRealm.where(Group.class).equalTo("id", event.getPeer().getPeerId()).findFirst();
if (group != null) {
chat = new Chat(event.getPeer(), eventRealm, group);
bgRealm.insertOrUpdate(chat);
} else {
Timber.e("Chat == null, group == null, can't create Chat");
}
}
if (chat != null) {
if (event.getAction() != null) {
if (ServiceAction.ACTION_GROUP_CREATED.equals(event.getAction().getType())
&& event.getSenderId() != getSelfUserId()) {
// если группу создал не я
chat.setUnreadCount(1);
}
if (!ServiceAction.ACTION_GROUP_CREATED.equals(event.getAction().getType())) {
chat.setUnreadCount(1);
}
}
bgRealm.insertOrUpdate(chat);
} else {
Timber.e("Chat == null or group == null, can't create Chat in saveEventToRealm");
}
}
}