liman.io

liman.io

An illustration of a man fixing a bug in source code

Tackling AttributeGraph precondition failure: setting value during update using Realm in SwiftUI

RealmSwiftUI

published on 2022-11-23

📚  This article is part of a series on Realm and SwiftUI:
  • 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. ✌🏼

Daniel Fürst © 2023 • Legal Notice • Privacy Policy