Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone Core Data Lightweight Migration Cocoa error 134130: Can't find model for source store

Folks,

Lightweight migration is failing for me 100% of the time on this line:

[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]

with the error:

Error: Error Domain=NSCocoaErrorDomain Code=134130 UserInfo=0x4fbff20 "Operation could not be completed. (Cocoa error 134130.)"
"Can't find model for source store";

Here is my managed object context, model, and persistent store:

- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }
    return managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel != nil) {
        return managedObjectModel;
    }

    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
    return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Locations.sqlite"]];

    NSError *error;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

    // Allow inferred migration from the original version of the application.
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
        NSLog(@"Error: %@",error);
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator;
}

I have two versions of my model in my project: a version 4 and a version 5. If I set my version 4 as default, it works fine. If I select "Design -> Data Model -> Add Model Version" (as described by this post), make a change, Design -> Data Model -> Set Current Version, build and run, it will fail with the aforementioned "Can't find model for source store" error. Set model back to version 4, no problems, addPersistentStoreWithType. Alternatively, if I add model version and make no changes, simply go from version 4 to 5 without adding any new fields, no problems. If I then try to go from 5 to 6, the aforementioned error.

This code is failing on both Simulator and Phone. I read several prescriptions calling for deleting and reinstalling the app, which does work for both Simulator and Phone, but I am afraid that when I release this to real users it will break my installed base since they won't be able to delete and reinstall - App Store will auto-upgrade them.

This code worked in releases past with no changes on my part - hence my ability to make it all the way up to version 4. I recently upgraded to XCode 3.2.3 building for iOS4, which may have something to do with this.

Is anyone else having this issue all of a sudden now like I am? Has anyone managed to work past it? Thanks.

PS - For Googlers who stumble on this page, here are all the relevant pages you might consider reading, below. Unfortunately none of these solved my issue.

  • Implementation of "Automatic Lightweight Migration" for Core Data (iPhone)
  • http://iphonedevelopment.blogspot.com/2009/09/core-data-migration-problems.html
  • https://stackoverflow.com/questions/2925918/iphone-core-data-lightweight-migration-error-reason-cant-find-model-for-sour
  • iPhone Core Data "Automatic Lightweight Migration"
  • http://www.iphonedevsdk.com/forum/iphone-sdk-development/38545-coredata-migration-issues.html

UPDATE

While this is not a real fix, it does avoid the scenario of a crashing client: simply delete the database file:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {



    // Delete file
    if ([[NSFileManager defaultManager] fileExistsAtPath:storeUrl.path]) {
        if (![[NSFileManager defaultManager] removeItemAtPath:storeUrl.path error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) 
    {
        // Handle the error.
        NSLog(@"Error: %@",error);
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();

    }
}    

UPDATE 2

Here is what happens when I inspect VersionInfo.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>NSManagedObjectModel_CurrentVersionName</key>
        <string>Profile 5</string>
        <key>NSManagedObjectModel_VersionHashes</key>
        <dict>
                <key>Profile</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        ZIICGgMBreuldkPXgXUhJwKamgwJzESM5FRTOUskomw=
                        </data>
                </dict>
                <key>Profile 2</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        tEB7HrETWOSUuoeDonJKLXzsxixv8ALHOoASQDUIZMA=
                        </data>
                </dict>
                <key>Profile 3</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        qyXOJyKkfQ8hdt9gcdFs7SxKmZ1JYrsXvKbtFQTTna8=
                        </data>
                </dict>
                <key>Profile 4</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        lyWDJJ0kGcs/pUOModd3Q1ymDvdRiNXui4NCpLxDFSw=
                        </data>
                </dict>
                <key>Profile 5</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        V4PyRK1ezj3xK1QFRCTVzGOqyJhEb7FRMzglrTsP0cI=
                        </data>
                </dict>
        </dict>
</dict>
</plist>

Here is the code that I wrote to inspect my model (note I had to go out and add a base64 encoder, since that is what is in the VersionInfo.plist file)

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {


    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeUrl error:&error];
    NSLog(@"%@",storeMeta);
    id someObj = [[storeMeta objectForKey:@"NSStoreModelVersionHashes"] objectForKey:@"Profile"];
    NSLog(@"%@",someObj);
    NSLog(@"%@",[NSString base64StringFromData:someObj length:[someObj length]]);

And here is the debug output:

{
    NSPersistenceFrameworkVersion = 310;
    NSStoreModelVersionHashes =     {
        Profile = <97258324 9d2419cb 3fa5438c a1d77743 5ca60ef7 5188d5ee 8b8342a4 bc43152c>;
        SerializedMessage = <4530863c d943479a edfb4dfb 5059c28d d6137dc4 d1153d36 ed52be49 11074f13>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
    );
    NSStoreType = SQLite;
    NSStoreUUID = "823FD306-696F-4A0F-8311-2792825DC66E";
    "_NSAutoVacuumLevel" = 2;
}

<97258324 9d2419cb 3fa5438c a1d77743 5ca60ef7 5188d5ee 8b8342a4 bc43152c>
lyWDJJ0kGcs/pUOModd3Q1ymDvdRiNXui4NCpLxDFSw=

As you can see, that last line that starts with 'ly' matches Profile 4 in VersionInfo.plist...hence I see no reason why it should be failing. Any other ideas?

like image 868
esilver Avatar asked Jun 30 '10 04:06

esilver


3 Answers

I read several prescriptions calling for deleting and reinstalling the app, which does work for both Simulator and Phone, but I am afraid that when I release this to real users it will break my installed base since they won't be able to delete and reinstall.

This is a problem caused by Xcode not removing old momc files from simulator/dev-device when a the model file is changed e.g. changing the name. The old file remains which causes confusion. This is something you only see during development because it is an artifact of the way that Xcode manipulates the app bundle without completely reinstalling it every time as must happen with a release version.

You can confirm this logging the return of:

[[NSBundle mainBundle] URLsForResourcesWithExtension:@"momc"subdirectory:nil];

... which should show you all the compiled model files in the app bundle

It is bad practice to rely on migration during development because it is very common for migration to fail if you are making changes to the model and store. You should only use migration after all the code is nailed down. I would also recommend regenerating your store from scratch every time you run. It is to easy to build up garbage in the store by changing up the model.

like image 71
TechZen Avatar answered Nov 20 '22 00:11

TechZen


I've read over your updated question. It's getting quite messy with model versions.

You should try and audit the version of the model that the existing store is actually asking for, and try to list all available models in the app bundle at runtime.


I look in my apps' model directory

NSString *modelDirectoryPath = [[NSBundle mainBundle] pathForResource:@"MyModel" ofType:@"momd"];

I'm not sure if developers normally do this, but I keep my model versions with different names.. so I have in there:

  • VersionInfo.plist
  • MyModel.mom
  • MyModel2.mom

The version hashes listed in the VersionInfo.plist should help you troubleshoot. Look for the version hash required by the existing persistent store, and see if you can locate it in the version hashes listed in VersionInfo.plist.

Actually, I can't see a way to write some code that will ask the persistent store what it's entity version hashes are. The NSPersistentStoreCoordinator or the NSMigrationManger seem to be doing that privately. i.e. they check the persistent store entity versions against the model that the store is loaded with.


Had another quick look, and it's available in the store meta data. Nice and easy!

NSError *error;
NSURL *storeURL = [NSURL fileURLWithPath:[[self class] storePath]];
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeURL error:&error];

And looking in storeMeta I get a key with

<CFString 0x7328050 [0x2724380]>{contents = "NSStoreModelVersionHashes"} = <CFBasicHash 0x7328340 [0x2724380]>{type = immutable dict, count = 5,
entries =>
    0 : <CFString 0x7328110 [0x2724380]>{contents = "MyEntityNameOne"} = <CFData 0x73281b0 [0x2724380]>{length = 32, capacity = 32, bytes = 0x143325cf121239ce156af2e2a1aad7d9 ... 976977fdf29fc013}
    1 : <CFString 0x7328130 [0x2724380]>{contents = "MyEntityNameTwo"} = <CFData 0x7328200 [0x2724380]>{length = 32, capacity = 32, bytes = 0x0ca6ecf1283d12bd3ca82af39b6b9f5d ... 149dd39a591e0c4d}
    ...    }

Should be easy to iterate over that NSStoreModelVersionHashes dictionary and log the version hashes your store requires.

Manually match that back to the ones available in VersionInfo.plist and see what's missing. Perhaps there's not one single model that contains all the required versions of the entities in your existing persistent store. That might happen due to (accidental?) edits on the model before or after setting up a new model version?

like image 4
ohhorob Avatar answered Nov 19 '22 23:11

ohhorob


I had esilver's exact problem and found this question via Google. However, the fix that worked for me wasn't anywhere else on SO (that I know), so here goes:

If there are multiple copies of your *.mom files (compiled object models) in your bundle, Core Data may become confused when attempting to migrate on your behalf.

Our problem was that each individual model file (Data.xcdatamodel, Data_V1.xcdatamodel, Data_V2.xcdatamodel, etc.) was not only inside the xcdatamodeld/ directory (which was included as something to compile in the build process), but also each file was also included in the "Compile Sources" list.

What this meant is that the resulting bundle had two sets of *.mom files: one inside xcdatamodeld/ and one at the top level. I think Core Data became very, very confused, and led to this error. Removing each xcdatamodel file from the "compile sources" and leaving the xcdatamodeld directory solved the problem for us (e.g. got auto-versioning up and running again). Hope this helps!

like image 4
makdad Avatar answered Nov 20 '22 01:11

makdad