Failed to find a currently active container for "Module Name"

Hi,

I had a SwiftData model and it was working fine, I had few records in it, but when I added to its Module file few extra properties I started to get the below error ! how to fix this ?

"Thread 1: Fatal error: failed to find a currently active container for Patient"

The reason of the error is that your new data model, after you made the changes, isn't compatible with your existing data. To handle the kind of issue, there are two options:

  1. Remove the existing data store, use the new data model to create a new store, and continue the development.

  2. Migrate the existing data store to the new data model.

In the development phase when my data model isn't stable, I typically go with option 1. By choosing this option, the existing data is lost, but that doesn't matter because the app is still under development.

If the app has been shipped, option 2 is the only choice, and you can implement it by versioning your models with VersionedSchema and SchemaMigrationPlan.

As an example, assuming that I have a SwiftData model named Item at the very beginning (version 1) and I would like to evolve the model to version 2 by:

  • Changing Item by adding a new attribute.
  • Adding a new model named Item2.

Here is the way to define the models in my version 2 app:

typealias Item = ItemSchemaV2.Item
typealias Item2 = ItemSchemaV2.Item2

enum ItemSchemaV1: VersionedSchema {
    static var versionIdentifier: Schema.Version {
        return Schema.Version(1, 0, 0) //"ItemSchemaV1"
    }
    
    static var models: [any PersistentModel.Type] {
        [Item.self]
    }

    @Model
    final class Item {
        var timestamp: Date = Date.now
        
        init(timestamp: Date = .now) {
            self.timestamp = timestamp
        }
    }
}

enum ItemSchemaV2: VersionedSchema {
    static var versionIdentifier: Schema.Version {
        return Schema.Version(2, 0, 0) //"ItemSchemaV2"
    }
    
    static var models: [any PersistentModel.Type] {
        [Item.self, Item2.self]
    }

    @Model
    final class Item {
        var timestamp: Date = Date.now
        var title: String = ""

        init(timestamp: Date = .now, title: String = "") {
            self.timestamp = timestamp
            self.title = title
        }
    }
    
    @Model
    final class Item2 {
        var transformedTimestamp: String
        
        init(transformedTimestamp: String = "") {
            self.transformedTimestamp = transformedTimestamp
        }
    }
}

enum ItemsMigrationPlan: SchemaMigrationPlan {
    static var schemas: [any VersionedSchema.Type] {
        [ItemSchemaV1.self, ItemSchemaV2.self]
    }
    
    static var stages: [MigrationStage] {
        [migrateV1toV2]
    }
    
    static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: ItemSchemaV1.self, toVersion: ItemSchemaV2.self)
}

The above code uses lightweight migration stage (.lightweight(fromVersion:toVersion:)) because both of the changes are supported by lightweight migration.

In the case where your change is not supported by lightweight migration, you can use a custom migration stage (custom(fromVersion:toVersion:willMigrate:didMigrate:)). The following code example uses a custom migration stage to set Item.title to "new title" in the didMigrate closure:

    //static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: ItemSchemaV1.self, toVersion: ItemSchemaV2.self)
    static let migrateV1toV2 = MigrationStage.custom(fromVersion: ItemSchemaV1.self,
                                                     toVersion: ItemSchemaV2.self) { context in
        print("willMigrate: No preprocess needed.")
        
    } didMigrate: { context in
        print("didMigrate. Initialize the title after the migration.")
        if let items = try? context.fetch(FetchDescriptor<ItemSchemaV2.Item>()) {
            for item in items {
                item.title = "new title"
            }
            try? context.save()
        }
    }

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Failed to find a currently active container for "Module Name"
 
 
Q