3

I've started developing app with SwiftData and decided to move to VersionedSchema recently and it just fails when I try to add a new version of a schema with Code=134504 "Cannot use staged migration with an unknown coordinator model version."

When I initially added version and named it v1, all worked fine, but making any changes to future schemas bring the same error. (right now I'm on V2, but I just dropped data on my development devices).

import Foundation
import SwiftData

enum SchemaV2: VersionedSchema {
    static var versionIdentifier: Schema.Version = Schema.Version(2, 0, 0)
    
    static var models: [any PersistentModel.Type] {
        [..., cardModel.self]
    }
    
    ...other models...

    @Model
    final class cardModel {
        var bank: bankModel
        var name: String?
        
        init(bank: bankModel, name: String? = nil) {
            self.bank = bank
            self.name = name
        }
    }
}

SchemaV3:

import Foundation
import SwiftData

enum SchemaV3: VersionedSchema {
    static var versionIdentifier: Schema.Version = Schema.Version(3, 0, 0) 
    
    static var models: [any PersistentModel.Type] {
        [..., cardModel.self]
    }

    ...other models...
    
    @Model
    final class cardModel {
        var bank: bankModel
        var name: String?
        var rewardType: RewardType?
        
        init(bank: bankModel, 
             name: String? = nil,
             rewardType: RewardType? = .cash
        ) {
            self.bank = bank
            self.name = name
            self.rewardType = rewardType
        }
    }
}

MigrationPlan:

import SwiftData

enum MigrationPlan: SchemaMigrationPlan {
    static var stages: [MigrationStage] {
        [
            MigrateV1toV2, MigrateV2toV3
        ]
    }
    
    static var schemas: [any VersionedSchema.Type] {
        [SchemaV1.self, SchemaV2.self, SchemaV3.self
        ]
    }
    
    static let MigrateV1toV2 = MigrationStage.lightweight(
        fromVersion: SchemaV1.self,
        toVersion: SchemaV2.self
    )
    
// I want to use a custom migration here, but even lightweight fails

    static let MigrateV2toV3 = MigrationStage.lightweight(
        fromVersion: SchemaV2.self,
        toVersion: SchemaV3.self)
}

Not too sure how can I proceed, since I have versionIdentifier in every schema and they are semver. Clean builds, Mac reload, beta Xcode were tried as well with no luck. Searching for unknown coordinator model version didn't help much.

p.s.I initialise SchemaV1 like this:

enum SchemaV1: VersionedSchema {
    static var versionIdentifier = Schema.Version(1, 0, 0) // Also tried to use such form with no luck: public static var versionIdentifier: Schema.Version {.init(1, 0, 0)}
    static var models: [any PersistentModel.Type] {
        [..., cardModel.self]
    }
    ...models...
}

3 Answers 3

6

I encountered this exact problem when transitioning from an unversioned schema to a versioned one.

The issue for me was that I didn't define all my models in the V1 schema, only the one that had changed. Defining all models resolved the issue.

The error essentially means "I can't determine from which version to start migrating."

The migrator examines your current database and compares its schema with schema generated by each of your versioned schemas. If it doesn't find a match, it fails with this error. If it does, it starts migrating from this version up.

This is what happened to me. The migrator looked at schema generated by my V1 version schema, it produced 1 table instead of 3 (I have 3 models), and concluded, "This is not the correct version to start migration" because the current database has three tables, not one.

So, make sure your database schema and schema generated by models in some of your version schemas are the same.

Tip: In your old version schemas, there is no need to copy and paste all the model code. You only need the code that participates in schema creation (stored attributes and relationships, basically), because those copies of the models are ony needed to calculate the old schemas to determine from which one to start migrating.

Sign up to request clarification or add additional context in comments.

4 Comments

Apparently my problem was slightly related, I had an extra model in my first schema by mistake. But main problem seemed to be that swiftdata couldn't update db from non-versioned to v1 to v2 in one go. So I had to release V1 version first for everyone to update, and after that v2 and new models would work.
From my understanding you should of do the following: 1) Non-versioned is the V1 and then your V1 and V2 should go into one version. In the end you'd have two versions — the original schema in V1 and updated schema in V2. But I glad it worked out for you in the end.
@AleksKuznetsov you say "So I had to release V1 version first for everyone to update" but how do you ensure everyone updates and opens the app so this happened for all users before releasing the next version? :thinking:
@mesqueeb I'm still in TestFlight, so I just blocked old version, waited some time and released new one. But I'm not sure how to replicate that in prod.
4

I was running into this issue. I'm a long time CoreData user - relatively new to SwiftData.

My issue was this: I was not including ALL MODELS in my latest Schema models.

Example:

V1

enum ModelSchemaV1: VersionedSchema {
    static var versionedIdentifier = Schema.Version(1, 0, 0)
    
    static var models: [any PersistendModelType] {
        [
            User.self,
            Book.self
        ]
    }
}

V2

enum ModelSchemaV2: VersionedSchema {
    static var versionedIdentifier = Schema.Version(2, 0, 0)
    
    static var models: [any PersistendModelType] {
        [
            User.self, // <-- THIS
            Book.self, // <-- THIS
            Pencil.self,
            Pen.self
        ]
    }
}

I had failed to include the previous schema's models in the new schema's models.

Once I did this, everything was happy.

Comments

1

My workaround if I got this error, was to create a ModelContainer using the original schema (so V1) in your case.

Then you can throw away that container and try initializing a new ModelContainer with your current schema and migration plan.

Something like

// In something like initializeModelContainer(storeURL: URL)

do {
    let config = ModelConfiguration(url: storeURL, cloudKitDatabase:.none)
    let schema = Schema(versionedSchema: SchemaV3.self)
    let modelContainer = try ModelContainer(for: schema,
                                            migrationPlan: MigrationPlan.self,
                                            configurations: config)

    self.modelContainer = modelContainer
} catch SwiftDataError.loadIssueModelContainer {
    // Added a counter so that if the model creation fails for some other reason, we don't end up in an infinite loop.
    loadIssueModelContainerCount += 1

    guard loadIssueModelContainerCount < 2 else {
        fatalError("Failed second attempt to create the model container.")
            }

    // Initialize a throw away container for your old model
    let config = ModelConfiguration(url: storeURL, cloudKitDatabase:.none)
    let schema = Schema(versionedSchema: SchemaV1.self)
    _ = try ModelContainer(for: schema, configurations: config)

    // Call this method to try again with our current schema.
    return initializeModelContainer(storeURL: storeURL)
} catch {
    fatalError("Failed to create the model container: \(error)")
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.