CoreData Migration Failure - NSCocoaErrorDomain Code=512

Hey Team,


We are seeing some random crashes for CoreData only on iOS 9 devices. We are primarily seeing two errors when Core Data performs lightweight migration when setting up the Stack -


We have no clue about what this error could be

"Error Domain=NSCocoaErrorDomain Code=512 \"The file couldn\U2019t be saved.\"


2. The error code translates to SQLite Error code 14. [Error code is "Domain=NSCocoaErrorDomain Code=134110", "NSSQLiteErrorDomain Code=14" https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Miscellaneous/CoreData_Constants/#//apple_ref/doc/constant_group/Migration_Error_Codes , https://www.sqlite.org/rescode.html#cantopen ]


Error Domain=NSCocoaErrorDomain Code=134110 \"An error occurred during persistent store migration.\" UserInfo=
{  sourceURL=file:///var/mobile/Containers/Data/Application/BFD91E93-5977-4135-A454-5EBDF8EE53E4/Library/Database/DB.sqlite,
reason=Can't copy source store to destination store path, destinationURL=file:///var/mobile/Containers/Data/Application/BFD91E93-5977-4135-A454-5EBDF8EE53E4/Library/Database/.DB.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3,
NSUnderlyingError=0x127fd31e0 {Error Domain=NSSQLiteErrorDomain Code=14 \"(null)\"
UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/BFD91E93-5977-4135-A454-5EBDF8EE53E4/Library/Database/.DB.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3,


reason=Failed to open destination database}}}";


We don't know what could be causing these issues. Also, the directory being protected via "NSFileProtectionComplete" option does not seem to be setup right.


Some additional datapoints that we have from Crashlytics -

1. This crash happens only on iOS 9 devices

2. Almost 70-80% of the times, the user has low RAM

3. We are not able to reproduce this migration issue on our test devices

4. We dropped support for "Vaccum option" for the latest version where we are seeing the crashes

5. We are logging the metadata and noticed that the NSPersistenceFrameworkVersion also changed from 640 to 641 from our last version of the app


We would really appreciate any help/pointers in how to fix this issue. Thanks!


Snippet from CoreData stack setup is as below -


# pragma mark - Core Data Stack Setup
- (NSManagedObjectContext *)getMainContext{

    NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [managedObjectContext setUndoManager:nil];
    [managedObjectContext setPersistentStoreCoordinator:[self getPersistentStoreCoordinator]];
    [managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
    return managedObjectContext;
}
- (NSPersistentStoreCoordinator*)getPersistentStoreCoordinator{

    NSPersistentStoreCoordinator *persistentStoreCoordinator = nil;

    NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
    NSManagedObjectModel *objectModel = [[NSManagedObjectModel alloc]
                                         initWithContentsOfURL:[NSURL fileURLWithPath:path]];
    NSDictionary *storeOptions =  @{ NSMigratePersistentStoresAutomaticallyOption: @YES,
                                     NSInferMappingModelAutomaticallyOption: @YES };
    NSError *error = nil;

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel];
    NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                                  configuration:nil
                                                                                            URL:[self storeURL]
                                                                                        options:storeOptions
                                                                                          error:&error];
    if (!persistentStore) {
        NSLog(@"error: %@", error);
    }

    return persistentStoreCoordinator;
}
-(NSURL *)storeURL{

    NSString *databaseFileName = @"DB.sqlite";
    NSString *appDatabaseFilePath = [[self sharedDatabasePath] stringByAppendingPathComponent:databaseFileName];
    return [NSURL fileURLWithPath:appDatabaseFilePath];
}
- (NSString *)sharedDatabasePath{

    NSString *sharedDocumentsPath = nil;
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    sharedDocumentsPath = [libraryPath stringByAppendingPathComponent:@"Database"] ;

    NSFileManager *manager = [NSFileManager defaultManager];
    BOOL isDirectory;
    if (![manager fileExistsAtPath:sharedDocumentsPath isDirectory:&isDirectory] || !isDirectory) {
        NSError *error = nil;
        NSDictionary *attr = [NSDictionary dictionaryWithObject:NSFileProtectionComplete
                                                         forKey:NSFileProtectionKey];
        [manager createDirectoryAtPath:sharedDocumentsPath
           withIntermediateDirectories:YES
                            attributes:attr
                                 error:&error];
        if (error)
            NSLog(@"Error creating directory path: %@", [error localizedDescription]);
    }

    return sharedDocumentsPath;
}

Replies

I only just saw this post. Maybe its a bit late for a response but I had a sort of, kind of, the same problem a while ago.

I was using Swift but that doesn’t really matter I guess.


I got it fixed using a NSMergePolicy object and passing it into managedObjectContext.setMergePolicy instead of

[managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];