Closed jhoanarango closed 2 hours ago
➤ PM Bot commented:
Jira ticket: RCORE-2133
Transferring to Core repo as this is an exception thrown deep in Core.
Anything on this? This bug is really affecting my app and my user's experience.
Our app is also greatly affected. Each version has thousands of crashes. What are the common causes of such crashes? Thanks a lot.
Our app is also greatly affected. Each version has thousands of crashes. What are the common causes of such crashes? Thanks a lot.
I think it would help if you post your stacktrace & log output from Firebase showing you the moment of the crash. We may be able to compare and allow the developers to have more evidence and point them to the right direction.
@nirinchev anyone that we can tag into this issue? It's been sitting here with no response. Thanks a lot.
Hi @jhoanarango thanks for reporting this. Are you able to share any more information to help us track this down?
RealmManager.saveLive
?RealmManager.saveLive
code?Internal note: realm-swift 10.50.1 uses core v14.6.2.
// Delete expired messages when the App starts
func delete(msg: Message) {
realm.delete(msg._to)
realm.delete(msg)
}
//Here is my scheme of the objects implementation:
open class Message:Object {
@objc dynamic var pId = ""
@objc dynamic var folderId: String? = nil
@objc dynamic var date = Date.distantPast
@objc dynamic var flag = 0
@objc dynamic var hasAttachment = false
@objc dynamic var from:ContactItem?
var authResults = List<String>();
private var _to = List<ContactItem>()
}
//embedded objects
open class ContactItem: Object{
@objc dynamic var pId = ""
@objc dynamic var name: String? = ""
@objc dynamic var isRobot = false
@objc dynamic var lastUpdated:Date = Date.distantPast
private let _messages = LinkingObjects(fromType: Message.self, property: "from")
}
Is it because LinkingObject is used in embedded objects?
Seems like you are trying to delete an object that is already deleted.
I have checked whether the Object is invalidate before deleting it. Does this check work? Thanks a lot.
// Here is the delete function:
func delete<T: Object>(_ entity: T) {
if entity.isInvalidated {
return
}
autoreleasepool {
do {
if realm.isInWriteTransaction {
realm.delete(entity)
} else {
try realm.write {
realm.delete(entity)
}
}
} catch let error as NSError {
}
}
}
I am not sure how the Swift SDK operation translate into core. @nirinchev can you help here?
Hi @jhoanarango thanks for reporting this. Are you able to share any more information to help us track this down?
- What realm operations are you doing in
RealmManager.saveLive
?- Can you share the schema of the objects being deleted in the transaction created by the
RealmManager.saveLive
code?- The exception has to do with a link relationship, so we are looking for anything unusual in the object graph of the objects being deleted (ex: embedded objects? lists of links with duplicate links? link cycles? etc)
Internal note: realm-swift 10.50.1 uses core v14.6.2.
Thanks for the reply @ironage,
Here are the steps my app is taking. As noted before, I have an object that takes care of all realm operations. This object has some methods that save/queries/modifies the objects handled by Realm.
When a user downloads the information from our servers, it saves what we call "opentime trips" and it also creates and saves "Tracked Events". Events are calendar events from the user's calendar and they have a unique ID that must be tracked in order for us to make any changes or delete those events. These operations are handled once the user downloads data from our servers. The tracked events function happens first and then is followed by saving the opentime trips. Opentime trips are also delete or added depending on the new data download from the servers. For example, if an opentime trip is no longer on our servers and the user download the new data, then the app will filter out those trips that are no longer on the list and deletes them. The same operation is being done for the calendar events.
Saving Opentime Trips
Opentime Schema:
class OpenTime: Object, Decodable {
// MARK: - Properties
@Persisted var opentimeTrips : List<OpenTimeTrip>
// Primary Key
@Persisted(primaryKey: true)
var month: String = "0326"
}
OpenTimeTrip Schema:
class OpenTimeTrip: Object, Decodable {
// MARK: - Properties
@Persisted var DATE : String = ""
@Persisted var arrive : String = ""
@Persisted var blkHours : String = ""
@Persisted var credit : String = ""
@Persisted var dates : String = ""
@Persisted var days : Int?
@Persisted var depart : String = ""
@Persisted var isTb : Int?
@Persisted var layover : String = ""
@Persisted var pairing : String = ""
@Persisted var report : String = ""
@Persisted var isFavorite : Bool = false
@Persisted var isDislike : Bool = false
@Persisted var isPending : Bool = false
@Persisted var status : String = ""
@Persisted var belongsTo : String = ""
@Persisted var isBlocked : Int = 0
@Persisted var tripWorth : String? = "" // Used to show the worth for the scheduled pairing on the OpenTimeViewController
@Persisted var position : List<String>
@Persisted var forSwap : Bool = false
@Persisted var isDisqualified : Bool? = false
@Persisted var isPremium : Bool? = false
@Persisted var timeInOpentime : String? = ""
@Persisted var disqualifiedMessage: String? = ""
@Persisted var isSplit : Bool? = false
@Persisted var splitLegs : List<Int>
// Primary Key
@Persisted(primaryKey: true)
var id: String = ""
// #### Other code
}
RealmManager/saveLive
static func saveLive(_ openTime: [OpenTime]) {
setRealm()
guard let openTime = openTime.first else { return }
let openTimeTripIds: [String] = openTime.opentimeTrips.map { $0.id }
if let tripsInRealm = realm?.objects(OpenTimeTrip.self).filter("belongsTo = '\(openTime.month)'") {
let tripsToDelete = tripsInRealm.filter("NOT id IN %@", openTimeTripIds)
do {
try realm?.safeWrite {
realm?.delete(tripsToDelete)
}
} catch {
print("Error deleting OpenTime Trips in Realm")
}
}
do {
try realm?.safeWrite {
/// Keeps the favorite trips from open time if they are still available
if let favoriteTrips = self.getFavoriteTrips() {
for trip in openTime.opentimeTrips {
for favoriteTrip in favoriteTrips where trip.DATE == favoriteTrip.DATE && trip.pairing == favoriteTrip.pairing {
trip.isFavorite = favoriteTrip.isFavorite
}
}
}
save([openTime])
}
} catch {
}
}
Event Tracker
class EventTracker: Object {
// MARK: - Properties
@Persisted var trackedEvents: List<TrackedEvent>
/// Primary Key
@Persisted(primaryKey: true)
var month: String = ""
// MARK: - Life Cycle
init(month: String, trackedEvents: [TrackedEvent]) {
self.month = month
let trackedEventsToSave = List<TrackedEvent>()
trackedEventsToSave.append(objectsIn: trackedEvents)
self.trackedEvents = trackedEventsToSave
super.init()
}
required override init() {
super.init()
}
}
Tracked Event
class TrackedEvent: Object {
// MARK: - Properties
@Persisted
var eventID: String
// Primary Key
@Persisted(primaryKey: true)
var id: String = ""
// MARK: - Life Cycle
init(id: String, eventID: String) {
self.id = id
self.eventID = eventID
super.init()
}
required override init() {
super.init()
}
}
RealmManager/saveEventTracker
static func saveEventTracker(_ tracker: EventTracker) -> [String]? {
setRealm()
var eventIdsToDelete: [String] = []
var trackedEventList: [TrackedEvent] = []
trackedEventList.append(contentsOf: tracker.trackedEvents)
let trackedEventIds = trackedEventList.map { $0.id }
if let eventTracker = realm?.objects(EventTracker.self).filter("month = '\(tracker.month)'").first {
let trackEventsToDelete = eventTracker.trackedEvents.filter("NOT id IN %@", trackedEventIds)
eventIdsToDelete = trackEventsToDelete.map { $0.eventID } as [String] /// The event ID's that will be returned so that we can remove the event.
do {
try realm?.safeWrite {
realm?.delete(trackEventsToDelete)
}
} catch {
print("Catch Error in \(#file), line \(#line)")
}
}
self.save([tracker])
return eventIdsToDelete
}
@ironage, I would like to also note that, this issue started happening after I updated Realm at some point.
Also, the "EventTracker" is a feature that is optional to the user. When turned off, the crashing goes away. The saving of the "Opentime" objects is not an option the user can turn off. What I am trying to point out is that the issue to me does not seem to be in the "saveLive", but on the track events. Also, Firebase's crashlytics show the following message as the title for the crash.
Key '2169' not found in 'TrackedEvent' when nullifying incoming links
@ironage
In case you want to know what the safeWrite is..
extension Realm {
/// A more safe way of writing to disk.
/// - Parameter block: The block to write on discs
/// - Throws: Throws an issue if one is found.
func safeWrite(_ block: (() throws -> Void)) throws {
if isInWriteTransaction {
try block()
} else {
try write(block)
}
}
}
FYI: I see that recent version of realm-core(Realm Core v14.10.3) has a fix for this issue, Core#7828 and Core#7594 but When I upgraded the Realm SDK to 10.55.2(realm-core v14.11.0) and the issue still exists.
I had to remove the realm that handled this process in my app. Too many people having crashes and no real movement on here. Maybe look for an alternative where you are using Realm.
@jhoanarango @chenyanping01 thanks for your feedback. We never did get a repro from this specific issue but I do think the root cause is very likely fixed by https://github.com/realm/realm-core/pull/7830. That being said, a Realm affected by this issue may have been put into an invalid state if your app encountered this issue before the fix. There were assertions present in our code to prevent this from happening, but they were only enabled for debug builds, which you would have had off in a release build. If you are able to provide us with an affected Realm, we could inspect it to determine if this is indeed the case. It would also be useful for us if you can confirm that this exception is not found by any of your new users who started fresh from a version of Realm containing the fix. That being said, you still need a solution for your users who are affected by the invalid backlinks. If you are certain that this is the situation your users are in, one idea would be for you to manually duplicate your objects to another Realm and use that going forward.
@ironage thanks for the reply.
There were assertions present in our code to prevent this from happening, but they were only enabled for debug builds,
We got this crash issue from Firebase Crashlytics report. We are very sure that this is not only happening in Debug builds, as hundreds of users encounter crashes in each version. Can you help confirm that this assertion is only happening in Debug Builds?
If you are able to provide us with an affected Realm
Do you mean the realm version we used? I'm not sure which version this problem started, probably version 10.40. The version we are currently using is the latest version 10.52.2.
It would also be useful for us if you can confirm that this exception is not found by any of your new users who started fresh from a version of Realm containing the fix.
I can add custom logs to see if this exception is not found by any of your new users. I will feedback later.
one idea would be for you to manually duplicate your objects to another Realm and use that going forward.
It's hard to manually duplicate objects to another Realm and use that going forward. Because the table in the database may be very large, there may be problems with online user migration.
@chenyanping01
We got this crash issue from Firebase Crashlytics report.
Yes, but Key 'x' not found in 'y' when nullifying incoming links
is an exception which can be caught. The assertions that are only turned on in debug mode would be something like this array_backlink.cpp:112: Assertion failed: int64_t(value >> 1) == key.value
and would cause an abort.
Do you mean the realm version we used?
I mean, if you are able to, please send us the Realm file that is associated with one of these issues. Perhaps we can learn more from inspecting the data.
I can add custom logs
Thank you!
It's hard to manually duplicate objects
Understood. We may be able to make a migration to fix the data in place automatically, but before we go down that path, I would like to be sure that this is actually the case. Right now we are still guessing, because we have not been able to reproduce this issue. Any further information that can help us understand the root cause here would be greatly appreciated!
Thank you for the reply. @ironage
The assertions that are only turned on in debug mode
Sorry, I'm still confused, if this only turned on in debug mode. Why there are so many crashes in release mode. Did I miss something here.
@chenyanping01 apologies for the confusion, I will try to clarify. The exception reported in this issue is always enabled and that is what you appear to be experiencing. I would not classify it as a hard crash because you can use a try...catch to catch it in your code. The assertions I referred to earlier are not catchable, and those are only enabled in debug mode but you do not seem to be seeing those. Hope that helps clear things up.
As I mentioned earlier, if you are able to provide a reproduction for this we'd greatly appreciate it!
Thanks for clarification. @ironage Through observation of the two versions, this crash currently did not occur for users who newly installed the app. (I'm not 100% sure)
➤ jedelbo commented:
Based on the comments, I assume this has been fixed
How frequently does the bug occur?
Sometimes
Description
The 'Crashlytics' from Firebase is showing a crash on my project which is happening to a few users. I have not been able to reproduce this myself.
I have an Object that takes care of handling all Realm operations such as saving and getting data. I use this object to save an object I call "EventTracker". EventTracker has a list of 'TrackedEvent' which it has 2 properties, an event ID and an ID, both of type strings. These keep track of events the user has with their calendar and their are added/deleted depending on the user downloaded content.
It's been hard to find what is causing this crash since I've done all kinds of modifications on my code and they come back with the same outcome.
Any idea as to what may cause this error?
Stacktrace & log output
Can you reproduce the bug?
No
Reproduction Steps
No response
Version
10.50.1
What Atlas Services are you using?
Local Database only
Are you using encryption?
No
Platform OS and version(s)
iOS
Build environment
Xcode version: 15.1 Dependency manager and version: SPM