Fatal error on rollback after delete

I encountered an error when trying to rollback context after deleting some model with multiple one-to-many relationships when encountered a problem later in a deleting method and before saving the changes. Something like this:

do {
    // Fetch model
    modelContext.delete(model)
    // Do some async work that potentially throws
    try modelContext.save()
} catch {
    modelContext.rollback()
}

When relationship is empty - the parent has no children - I can safely delete and rollback with no issues. However, when there is even one child when I call even this code:

modelContext.delete(someModel)
modelContext.rollback()

I'm getting a fatal error: SwiftData/ModelSnapshot.swift:46: Fatal error: Unexpected backing data for snapshot creation: SwiftData._FullFutureBackingData<ChildModel>

I use ModelContext from within the ModelActor but using mainContext changes nothing. My ModelContainer is quite simple and problem occurs on both in-memory and persistent storage, with or without CloudKit database being enabled. I can isolate the issue in test environment, so the model that's being deleted (or any other) is not being accessed by any other part of the application. However, problem looks the same in the real app. I also changed the target version of iOS from 18.0 to 26.0, but to no avail.

My models look kind of like this:

@Model
final class ParentModel {
    var name: String

    @Relationship(deleteRule: .cascade, inverse: \ChildModel.parent)
    var children: [ChildModel]?

    init(name: String) {
        self.name = name
    }
}

@Model
final class ChildModel {
    var name: String
    @Relationship(deleteRule: .nullify)
    var parent: ParentModel?

    init(name: String) {
        self.name = name
    }
}

I tried many approaches that didn't help:

  1. Fetching all children (via fetch) just to "populate" the context
  2. Accessing all children on parent model (via let _ = parentModel.children?.count)
  3. Deleting all children reading models from parent:
for child in parentModel.children ?? [] {
    modelContext.delete(child)
}
  1. Deleting all children like this:
let parentPersistentModelID = parentModel.persistentModelID
            modelContext.delete(model: ChildModel.self, where: #Predicate { $0.parent.persistentModelID == parentPersistentModelID }, includeSubclasses: true)
  1. Removing @Relationship(deleteRule: .nullify) from ChildModel relationship definition

I found 2 solution for the problem:

  1. To manually fetch and delete all children prior to deleting parent:
let parentPersistentModelID = parentModel.persistentModelID
for child in try modelContext.fetch(FetchDescriptor<ChildModel>(predicate: #Predicate { $0.parent.persistentModelID == parentPersistentModelID })) {
    modelContext.delete(child)
}
modelContext.delete(parentModel)
  1. Trying to run my code in child context (let childContext = ModelContext(modelContext.container))

All that sounds to me like a problem deep inside Swift Data itself.

The first solution I found, fetching potentially hundreds of child models just to delete them in case I might need to rollback changes on some error, sounds like awful waste of resources to me.

The second one however seems to work fine has that drawback that I can't fully test my code. Right now I can wrap the context (literally creating class that holds ModelContext and calls its methods) and in tests for throwing methods force them to throw. By creating scratch ModelContext I loose that possibility.

What might be the real issue here? Am I missing something?

I managed to create a minimal repro example:

import SwiftData
import SwiftUI

@Model
final class ParentModel {
    var name: String
    @Relationship(deleteRule: .cascade, inverse: \ChildModel1.parent)
    var children: [ChildModel1]?
    @Relationship(deleteRule: .cascade, inverse: \ChildModel2.parent)
    var children2: [ChildModel2]?

    init(name: String) {
        self.name = name
    }
}

@Model
final class ChildModel1 {
    var name: String
    @Relationship(deleteRule: .nullify)
    var parent: ParentModel?

    init(name: String) {
        self.name = name
    }
}

@Model
final class ChildModel2 {
    var name: String
    @Relationship(deleteRule: .nullify)
    var parent: ParentModel?

    init(name: String) {
        self.name = name
    }
}

struct ContentView: View {
    @Environment(\.modelContext)
    private var modelContext

    var body: some View {
        List {
            Button("Create parent with children") {
                createParentWithChildren()
            }

            Button("Delete") {
                delete()
            }
        }
    }

    func createParentWithChildren() {
        let parent = ParentModel(name: "Parent")
        let child1 = ChildModel1(name: "Child 1")
        let child2 = ChildModel2(name: "Child 2")
        modelContext.insert(parent)
        modelContext.insert(child1)
        modelContext.insert(child2)
        child1.parent = parent
        child2.parent = parent
        try! modelContext.save()
    }

    func delete() {
        guard let parent = try! modelContext.fetch(FetchDescriptor<ParentModel>()).first else { return }

        modelContext.delete(parent)
        // This throws "Unexpected backing data for snapshot creation" fatal error
        modelContext.rollback()
    }
}

@main
struct PlaygroundAppApp: App {
    private let container: ModelContainer

    init() {
        let schema = Schema([ParentModel.self, ChildModel1.self, ChildModel2.self])
        let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
        container = try! ModelContainer(for: schema, configurations: [config])
    }

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

The fact that modulates if the problem occurs or not it number of different relationships on ParentModel. When there is only one relationship (e.g. only @Relationship(deleteRule: .cascade, inverse: \ChildModel1.parent) var children: [ChildModel1]?) everything seems to work fine. As soon as I add second relationship, the fatal error on rollback is being triggered if deleted model contains any active relationship. What is interesting - even if model have only one active relationship, let's say there is only 1 ChildModel1 that points to give model, the fatal error is being triggered on rollback.

Considering all this it looks to me like the problem actually lies inside Swift Data internals, so I've filled the feedback - FB22325366.

Thanks for filing the feedback report (FB22325366). Yeah, that does look like an issue on the framework side. I can reproduce the crash without the need of adding a second relationship with Xcode 26.4 (17E192) + iOS 26.4 (23E244) Simulator.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Fatal error on rollback after delete
 
 
Q