Error in SwiftData migrationPlan execution

I'm testing the new SwiftData to see if I can use it on one of my apps. Specifically I'm trying to learn how to use the schema migrations.

I made a new project using Xcode 15 beta 4. I selected to use SwiftData and iCloud.

I ran the generated project and I added a couple of items to the screen.

Then, I wanted to make a schema migration, so I changed the Item model from:

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

to also include a string title:

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

I also made some changes to the SwiftUI code to include an empty string when adding a new item, so it could compile:

let newItem = Item(timestamp: Date(), title: "")

And then I added a new file containing the migration, according to what I saw on the video sessions:

//
//  SwiftDataMigrations.swift
//  Test 1
//
//  Created by Diego on 12/07/23.
//

import Foundation
import SwiftData

enum ItemSchemaV1: VersionedSchema {
    static var versionIdentifier: String?
    
    static var models: [any PersistentModel.Type] {
        [Item.self]
    }

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

enum ItemSchemaV2: VersionedSchema {
    static var versionIdentifier: String?
    
    static var models: [any PersistentModel.Type] {
        [Item.self]
    }

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

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)
}

After that, I specified the migrationPlan in the app:

//
//  Test_1App.swift
//  Test 1
//
//  Created by Diego on 12/07/23.
//

import SwiftUI
import SwiftData

@main
struct Test_1App: App {
    var container = try! ModelContainer(
        for: Item.self,
        migrationPlan: ItemsMigrationPlan.self
    )

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
    }
}

And then I tried to run the app but it crashed on launch with this error:

SwiftData/ModelContext.swift:179: Fatal error: Container does not have any data stores

Does anyone have any idea about what I might be missing?

The only thing that didn't matched the videos was that when creating a ModelContainer, the code on the video showed var container = ModelContainer... but the compiler showed the error Call can throw, but errors cannot be thrown out of a property initializer, so I added the try!. Also, on the VersionedSchema, I had to add static var versionIdentifier: String?.

Other than that I have no idea.

Thanks in advance.

Post not yet marked as solved Up vote post of diegooo Down vote post of diegooo
1.2k views

Replies

I just checked with the latest version of Xcode (Beta 5) and this issue is still present.

Just posted a Feedback for this (FB12759179)

The only thing I see different to a migration I have working is that the versionIdentifier seems to have changed in Beta 5 to a non-optional string (the docs don't seem to have caught up). I've set them to a string of my choosing:

static var versionIdentifier: String = "V1"

Yes, @kharrison I noticed that when trying this in beta 5. I did almost the same as you, just copied the name of the migration inside the string. This is just a blind guess because I see absolutely no docs about this. I then tried a couple of different initializers with no success BUT... I think I got lightweight migrations working.

Amazingly, they seem to work if you just modify the @Model class directly and re-run the app. You don't have to specify a migration or anything. Just provide default values for new attributes and it works!!!

If you don't provide default values, the app will fail to start with an error that the migration failed.

In Beta 8, the versionIdentifier has been changed to be a Version Structure. Example below.

static var versionIdentifier: Schema.Version = .init(1, 0, 0)