iOS 26 SwiftData crash does not happen in iOS 16

I have a simple app that makes an HTTPS call to gather some JSON which I then parse and add to my SwiftData database. The app then uses a simple @Query in a view to get the data into a list.

on iOS 16 this works fine. No problems. But the same code on iOS 26 (targeting iOS 18.5) crashes after about 15 seconds of idle time after the list is populated. The error message is:

Could not cast value of type '__NSCFNumber' (0x1f31ee568) to 'NSString' (0x1f31ec718).

and occurs when trying to access ANY property of the list.

I have a stripped down version of the app that shows the crash available.

To replicate the issue:

  1. open the project in Xcode 26
  2. target any iOS 26 device or simulator
  3. compile and run the project.
  4. after the list is displayed, wait about 15 seconds and the app crashes.

It is also of note that if you try to run the app again, it will crash immediately, unless you delete the app from the device.

Any help on this would be appreciated.

Feedback number FB20295815 includes .zip file

Below is the basic code (without the data models)

The Best Seller List.Swift

import SwiftUI
import SwiftData

@main
struct Best_Seller_ListApp: App {
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer (for: NYTOverviewResponse.self)
    }
}

ContentView.Swift

import os.log
import SwiftUI

struct ContentView: View {
    @Environment(\.modelContext) var modelContext
    
    @State private var listEncodedName = String()
    
    
    var body: some View {
        NavigationStack () {
            ListsView()
        }
        
        .task {
            await getBestSellerLists()
        }
    }
    
    func getBestSellerLists() async {
        guard let url = URL(string: "https://api.nytimes.com/svc/books/v3/lists/overview.json?api-key=\(NYT_API_KEY)") else {
            Logger.errorLog.error("Invalid URL")
            return
        }
        do {
            let decoder = JSONDecoder()
            var decodedResponse = NYTOverviewResponse()
            
            //decode the JSON
            let (data, _) = try await URLSession.shared.data(from: url)
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            decodedResponse = try decoder.decode(NYTOverviewResponse.self, from: data)
            
            //remove any lists that don't have list_name_encoded. Fixes a bug in the data
            decodedResponse.results!.lists = decodedResponse.results!.lists!.filter { $0.listNameEncoded !=  "" }
            
            // sort the lists
            decodedResponse.results!.lists!.sort { (lhs, rhs) -> Bool in
                lhs.displayName < rhs.displayName
            }
            //delete any potential existing data
            try modelContext.delete(model: NYTOverviewResponse.self)
            
            //add the new data
            modelContext.insert(decodedResponse)
             
        } catch {
            Logger.errorLog.error("\(error.localizedDescription)")
        }
    }
}

ListsView.Swift

import os.log
import SwiftData
import SwiftUI

@MainActor
struct ListsView: View {
    //MARK: - Variables and Constants
    
    @Query var nytOverviewResponses: [NYTOverviewResponse]
    
    enum Updated: String {
        case weekly = "WEEKLY"
        case monthly = "MONTHLY"
    }
    
    //MARK: - Main View
    var body: some View {
        List {
            if nytOverviewResponses.isEmpty {
                ContentUnavailableView("No lists yet", systemImage: "list.bullet", description: Text("NYT Bestseller lists not downloaded yet"))
            } else {
                WeeklySection
                MonthlySection
            }
        }
        .navigationBarTitle("Bestseller Lists", displayMode: .large)
        .listStyle(.grouped)
    }
    
    
    var WeeklySection: some View {
        let rawLists = nytOverviewResponses.last?.results?.lists ?? []
        // Build a value-typed array to avoid SwiftData faulting during sort
        let weekly = rawLists
            .filter { $0.updateFrequency == Updated.weekly.rawValue }
            .map { (name: $0.displayName, encoded: $0.listNameEncoded, model: $0) }
            .sorted { $0.name < $1.name }
        
        return Section(header: Text("Weekly lists to be published on \(nytOverviewResponses.last?.results?.publishedDate ?? "-")")) {
            ForEach(weekly, id: \.encoded) { item in
                Text(item.name).font(Font.custom("Georgia", size: 17))
            }
        }
    }
    
    
    var MonthlySection: some View {
        let rawLists = nytOverviewResponses.last?.results?.lists ?? []
        // Build a value-typed array to avoid SwiftData faulting during sort
        let monthly = rawLists
            .filter { $0.updateFrequency == Updated.monthly.rawValue }
            .map { (name: $0.displayName, encoded: $0.listNameEncoded, model: $0) }
            .sorted { $0.name < $1.name }
        
        return Section(header: Text("Monthly lists to be published on \(nytOverviewResponses.last?.results?.publishedDate ?? "-")")) {
            ForEach(monthly, id: \.encoded) { item in
                Text(item.name).font(Font.custom("Georgia", size: 17))
            }
        }
    }
    
}
Answered by DTS Engineer in 860437022

Yeah, it can be that changes on the framework unintentionally trigger the crash, which will be a regression; it can also be the framework intentionally became stricter, which triggers the crash that should have been triggered in the previous version.

Given that you have confirmed your model schema matches the JSON schema, I think it is more like the former, and so would suggest that you file a feedback report. It will be a great help if you can attach a minimal sample that reproduces the issue though to your feedback report, and you can create that by following the steps I mentioned.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

What project?

The way you've written this, I'm guessing you've raised this as a bug and are just posting it here, too? https://feedbackassistant.apple.com/

If you haven't raised it and feel it's definitely a bug and not something you've done, please raise it. On that, you can't attach a project here so is it easy enough for you to simply provide the code in text form? If not, we can't really help you.

The error message seems to indicate a type mis-match, likely the data in your JSON data being a number, while the corresponding SwiftData attribute being a string. That mismatch triggers an error when your app saves the SwiftData store.

If you save your SwiftData store immediately after modelContext.insert(decodedResponse), as shown below, you will see the error:

func getBestSellerLists() async {
        ...
        modelContext.insert(decodedResponse)
        // Add the following code to save the context and trigger the error.
        do {
            try modelContext.save() // This triggers the error.
        } catch {
            print(error)
        }
        ...
}

You can probably use the following flow to figure out which piece of data triggers the type mismatch:

  1. Add the code snippet above to your project so you can trigger the crash in a controlled way.

  2. Replace the JSON data from the remote server with a local JSON file so you can easily change data.

  3. Remove part of the data from the JSON file, change your SwiftData models to match the schema, and then run your app to check if the crash is still there.

  4. Repeat step 3, until you find the culprit of the crash.

Given that the same thing works on the previous iOS version, I am super curious if it is indeed an issue on the framework side.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

I have double checked my models against the incoming JSON and it all matches up properly. I inserted the recommended code above and it indeed crashes on the modelContext.save but it never gets to the catch. It simply display a SIGABRT stating "An abort signal terminated the process. Such crashes often happen because of an uncaught exception or unrecoverable error or calling the abort() function."

Executing the exact same code works perfectly in iOS 18 without any changes. Calling the same endpoint and using the same JSON returned by that endpoint works without a hitch.

It seems to me that if the code works in iOS 18 and fails in iOS 26, that seems to be indicative of a change in the framework that I cannot check, no?

Accepted Answer

Yeah, it can be that changes on the framework unintentionally trigger the crash, which will be a regression; it can also be the framework intentionally became stricter, which triggers the crash that should have been triggered in the previous version.

Given that you have confirmed your model schema matches the JSON schema, I think it is more like the former, and so would suggest that you file a feedback report. It will be a great help if you can attach a minimal sample that reproduces the issue though to your feedback report, and you can create that by following the steps I mentioned.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

iOS 26 SwiftData crash does not happen in iOS 16
 
 
Q