SwiftData Crashes After Modifying The VersionedSchema More Than Once

Originator:minimaappslimited
Number:rdar://FB13200039 Date Originated:23/09/2023
Status:Open Resolved:
Product:SwiftData Product Version:iOS 17
Classification: Reproducible:
 
I've been stuck on this one for quite a while now, and I'm starting to become more and more convinced this is an issue with Xcode 15 Beta RC.

Just to give you some context I seem to be getting the following crash after modifying my schema (adding new properties) for the the second time. Below is the crash that is occurring on my device & simulator.

```
Unresolved error loading container Error Domain=NSCocoaErrorDomain Code=134130 "Persistent store migration failed, missing source managed object model." UserInfo={URL=file:///Users/xxxxx/Library/Developer/CoreSimulator/Devices/23B8CDDD-CC5F-4A1C-B0F4-CF89C77B7ECF/data/Containers/Data/Application/235A14D7-6492-439F-BB4D-B18498D80970/Library/Application%20Support/default.store, metadata={
    NSPersistenceFrameworkVersion = 1327;
    NSStoreModelVersionChecksumKey = "dia3s8Q2+lqw669j9+RcPLQ+06yu0x6BBTZ4cXoQ1os=";
    NSStoreModelVersionHashes =     {
        Category = {length = 32, bytes = 0x187754bb 36c51a62 85ede16f 4b2a3912 ... 57326030 2de7ef77 };
        Item = {length = 32, bytes = 0xa7e4be4d ddd86d36 f71799b0 bc69dcb4 ... 83d47dfe d433fc01 };
    };
    NSStoreModelVersionHashesDigest = "G/Tk4lzyeNBXzf5+7qxbd+isF8uFnSaC5LtUCCkC8GQwaG1d9Di0eJ10NQEyPgwRczoYeYAMYG8ai4RooEhH9w==";
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
        "1.2.0"
    );
    NSStoreType = SQLite;
    NSStoreUUID = "A99894EA-FA7B-4CA7-AEB7-6DEE42843EC0";
    "_NSAutoVacuumLevel" = 2;
}, reason=Can't find model for source store}
```

I currently have 5 versions of my Schemas there's two of them

- Item
- Category

Below is a minified changelog of what has changed between versions.

- Version 1 (Initial Version)
- Version 2 (Lightweight Migration - Property is renamed in Item)
- Version 3 (Custom Migration - New Property is added to Item both are bools)
- Version 4 (Custom Migration - New Property is added to Category which is a transformable)
- Version 5 (Custom Migration - New Property is added to Item which is a string)

It's quite a large file with all of the version schema's etc so i've created a gist [here](https://gist.github.com/tunds/7f45a4c815ea85e1721f52859e161388) for you to see all of the changes that have been made between Version 1 up until Version 5.

The problem that I'm seeing is that between migration for V1 up until V4 everything is fine. It's only until SwiftData attempt to migrate V4 to V5 and I get the crash that I have provided above, and V5 only has a new string property which shouldn't be causing a crash since I've done 2 custom migrations that were all fine before V5 so this seems really strange even tho my migration plan is setup properly which you can see below.

```
enum ToDosMigrationPlan: SchemaMigrationPlan {
    static var schemas: [VersionedSchema.Type] {
        [ToDosSchemaV1.self,
         ToDosSchemaV2.self,
         ToDosSchemaV3.self,
         ToDosSchemaV4.self,
         ToDosSchemaV5.self]
    }
    
    static var stages: [MigrationStage] {
        [
            migrateV1toV2,
            migrateV2toV3,
            migrateV3toV4,
            migrateV4toV5
        ]
    }
    
    // V1 to V2
    static let migrateV1toV2 = MigrationStage.lightweight(
        fromVersion: ToDosSchemaV1.self,
        toVersion: ToDosSchemaV2.self
    )
    
    // V2 to V3
    static let migrateV2toV3 = MigrationStage.custom(
        fromVersion: ToDosSchemaV2.self,
        toVersion: ToDosSchemaV3.self,
        willMigrate: nil,
        didMigrate: { context in
            
            let items = try? context.fetch(FetchDescriptor<ToDosSchemaV3.Item>())
            
            items?.forEach { item in
                item.isFlagged = false
                item.isArchived = false
            }
            
            try? context.save()
        })
    
    static let migrateV3toV4 = MigrationStage.custom(
        fromVersion: ToDosSchemaV3.self,
        toVersion: ToDosSchemaV4.self,
        willMigrate: nil,
        didMigrate: { context in
            
            let categories = try? context.fetch(FetchDescriptor<ToDosSchemaV4.Category>())
            categories?.forEach { category in
                category.color = UIColor(possibleColors.randomElement()!)
            }
            
            try? context.save()
            
        })
    
    static let migrateV4toV5 = MigrationStage.custom(
        fromVersion: ToDosSchemaV4.self,
        toVersion: ToDosSchemaV5.self,
        willMigrate: nil,
        didMigrate: { context in
            
            // TODO: Handle setting some custom data here with defaults

        })
}
```

Has anyone come across this or got any ideas as to what the problem may be?


I've tried the following:

- Making sure the model container is only created once
- Testing out each migration phase from V1 up until V4 and this is fine
- On a real device which is the same as the simulator

Deleting the app off the device and/or sim and running it fresh is all fine. But I can't tell peeps to delete the app of their device. Since the whole point of a migration is to help me migrate the data which it seems be failing on after a 3rd change to the Schema.


I’ve also attached 3 Versions of the project so you can test out migrations and see the issue that I’m having pls run the builds in the stages that I’ve labelled them in.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!