Could not merge changes: with oldVersion = 0 and newVersion = 4

We're seeing a rare issue in the field that I haven't been able to reproduce. The app primarily uses a main queue managed object context, with a couple of other private queue contexts for specialized cases. Those cases do not modify objects that are also modified in the main queue context, so we haven't done anything to specifically handle merge conflicts. We shouldn't have any during normal operation.


In at least one case, a user transitions from background to foreground and back to background in a short period of time. One of the things we do when transitioning to inactive state is to save the main queue context. During this save, sometimes it appears that all of the objects loaded in the main queue context will become conflicted. When this happens, the conflicts are very odd:


Failed to save: Error Domain=NSCocoaErrorDomain Code=133020 "Could not merge changes." UserInfo={conflictList=(
"NSMergeConflict (0x11d8ec540) for NSManagedObject (0x11bf50990) with objectID '0xd00000000f340014 <x-coredata://36EBC17F-A244-4CE0-BB10-C0C5C2C3AFC1/Document/p973>' with oldVersion = 0 and newVersion = 4 and old object snapshot = { ... all attributes are null ... } and new cached row = { ... all attributes have the expected values ... }"


I've encountered merge conflicts in the past, and they're due to modifications made in two contexts simultaneously. Here, we aren't modifying simultaneously, the oldVersion value is 0 and the old object snapshot is an empty object (none of the attributes are set to a value).


Has anyone else seen this behavior? Is there an explanation for how an object could have an oldVersion = 0?


Also, the docs don't provide quite enough detail for me to understand the difference between an "object snapshot" and a "cached row".

My main concern is what, exactly, you're using to save the main context; and whether that's not accidentally violating containment. (And, naturally, how exactly you're constructing your contexts. NSManagedDocument does more than it may sound like it's doing, for instance.) Especially since some of the "save context" code I've seen has done various things like ignore warning return values and violate containment across threads.

Saves are done directly on the context. The return value is checked and a valid NSError object is passed to log the specific error if the save fails. Thread containment is correct. Virtually all of our Core Data access happens on the main thread in a context with NSMainQueueConcurrencyType. Further, we regularly run the app through Xcode with "-com.apple.CoreData.ConcurrencyDebug 1", which will raise an assertion if thread containment is violated.


The part I find the most curious is "oldVersion = 0" and the empty/new object attributes. As I said in the original message, I've seen merge conflicts in the past that were the result of a logic flaw, and the debug output for the conflicting objects make much more sense: non-zero version numbers and objects with their attributes set to something.

I faced a similar issue and setting the merge policy solved the issue.

 managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

Did anyone found any good resolution to this, I even already have 'managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy' but I still see this issue.

I don't clearly understand when I should want in-memory changes and when store changes. I'm not editing from two ends. Just from the simulator. And, I want the last change to reflect all across.

So, even if an entry was being edited from two ends simultaneously, the last one to be saved should be stored in the store. From the Using Core Data With CloudKit video it seems i'll have to take time stamps using a date object (from which I was removing hours minutes and seconds for sake of simplicity).

Could not merge changes: with oldVersion = 0 and newVersion = 4
 
 
Q