AttributeGraph precondition failure: setting value during update using Realm in SwiftUI
AttributeGraph precondition failure: setting value during updateusing Realm in SwiftUI
published on 2022-11-23
- Tackling `AttributeGraph precondition failure: setting value during update` using Realm in SwiftUI
- Updating Schema of Synced Realm and iOS App in Production
- Open Third-Party URLs in a SwiftUI App Using a Share Extension
- Infinite Scrolling List for Paginated Results from GraphQL with SwiftUI
- Synced Realm on iOS with SwiftUI using Sign-in with Apple for Authentication
With gitlapp’s beta version 0.46.1, fatal
AttributeGraph precondition failure: setting value during update errors started popping up in Sentry. Most of the time, the error occurred during the start of gitlapp but sometimes also at a later point in other views of the app. The error message stayed the same and always pointed to the very same line of third-party code, though. Regardless, I did not immediately jump to investigating this issue since only a marginal fraction of users was affected.
Around the same time, Apple published iOS 16 together with XCode 14. This new version of Xcode caused the warning
Publishing changes from within view updates is not allowed, this will cause undefined behavior to pop up a lot during the runtime of gitlapp. I was not alone in this, though, so I did not pay a lot of attention to the warning in the beginning.
On October 28, a user of gitlapp reported the
AttributeGraph precondition failure: setting value during update error because it consistently crashed gitlapp for them after updating to the beta version 0.49.3. Oddly enough, these crashes did not happen for them on version 0.46.8 which they upgraded from. So, I started my journey investigating this issue from the bug report.
Making the connection
Unfortunately, though, I could neither reproduce the error on my iPhone running iOS 16 nor on the simulator running iOS 15.5 or iOS 16 in either version of gitlapp’s beta. Hence, I pointed my attention back to Sentry which had a dozen records of the error along with stack traces. As mentioned earlier, they all pointed to the very same line of code in Realm. This line of code is part of Realm’s
@ObservedResults wrapper that enables seamlessly querying data from Realm within SwiftUI views. As such, the fatal error seemed to occur in all views that utilize Realm’s wrapper. Looking at the error message, I guessed that the wrapper was updating its variable during an update of the SwiftUI view which ultimately led to the crash. Why couldn’t I reproduce this scenario, though?
This line of thought reminded me of the runtime warnings in Xcode. Their message (i.e.,
Publishing changes from within view updates is not allowed, this will cause undefined behavior) now sounded very familiar given the fatal error’s message. Back in Xcode, it turned out that the runtime warnings indeed pointed to the very same line of code in Realm that the stack trace in Sentry pointed to. While a lot of people on Apple’s developer forum and elsewhere labeled the runtime warnings as a bug, I was worried that there is some truth to these warnings as they seemed to cause a crash in the case of gitlapp.
With this worry, I turned to Realm’s GitHub issues and found that other developers already reported the runtime warning in Xcode when using Realm. More importantly, the runtime warnings they observed pointed to the same line of code that I observed the crash in gitlapp point to. However, since no one observed any undefined behavior, I reported my observations on the issue. In particular, this includes the following partial stack trace that is common to all crashes in gitlapp caused by the discussed error:
Exception Type: EXC_CRASH (SIGABRT) Crashed Thread: 0 Application Specific Information: AttributeGraph precondition failure: %s. > AttributeGraph precondition failure: setting value during update: 89784. > Stack overflow in _Z23RLMAddNotificationBlockI10RLMResultsEP20RLMNotificationTokenPT_U13block_pointerFvP11objc_objectP19RLMCollectionChangeP7NSErrorEP7NSArrayIP8NSStringEPU28objcproto17OS_dispatch_queue8NSObject Thread 0 Crashed: 0 libsystem_kernel.dylib 0x37656abbc __pthread_kill 1 libsystem_pthread.dylib 0x3b7a67850 pthread_kill 2 libsystem_c.dylib 0x3162756a8 abort 3 AttributeGraph 0x36c141510 AG::precondition_failure 4 AttributeGraph 0x36c1256a4 AG::Graph::value_set 5 SwiftUI 0x310a1f870 Attribute.setValue 6 SwiftUI 0x3100b1290 GraphHost.flushTransactions 7 SwiftUI 0x3100e0af8 GraphHost.asyncTransaction<T> 8 SwiftUI 0x3100e618c AttributeInvalidatingSubscriber.invalidateAttribute 9 SwiftUI 0x3100b7f70 AttributeInvalidatingSubscriber.receive 10 SwiftUI 0x31021df7c AttributeInvalidatingSubscriber<T> 11 SwiftUI 0x3100b8b80 SubscriptionLifetime.Connection.receive 12 Combine 0x32ed98784 AnySubscriberBox.receive 13 Combine 0x32ed87a64 AnySubscriber<T> 14 gitlapp 0x20049cb04 [inlined] ObservableStoragePublisher.send (SwiftUI.swift:205) 15 gitlapp 0x20049cb04 [inlined] Sequence.forEach 16 gitlapp 0x20049cb04 ObservableStoragePublisher.send 17 gitlapp 0x20049dac8 ObservableStorage.value.willset (SwiftUI.swift:241) 18 gitlapp 0x2004ad448 ObservableStorage.value.setter 19 gitlapp 0x20049ef0c [inlined] ObservableStorage.value.setter 20 gitlapp 0x20049ef0c ObservedResults.Storage.setupValue (SwiftUI.swift:435) 21 gitlapp 0x2004a0704 ObservedResults.wrappedValue.getter (SwiftUI.swift:519) [...]
Since then, a few other GitHub users chimed in and noted that they encountered the same problem. It does not seem that any of them faced actual application crashes, though. While a developer of Realm noticed the issue, it does not seem that there is an imminent solution to the problem. Hence, I will cut back on my efforts in fixing the fatal error in gitlapp for now, waiting for further statements from Realm. While this is unfortunate, the fatal error only affects less than 5% of gitlapp’s users and I can now direct my focus on improving and implementing new features for the app. As soon as I can achieve significant progress on the matter, I will update this article. ✌🏼