CloudKit data is lost when reinstalling the app

We worked with SwiftData, and once CloudKit was integrated, the synchronization worked well. Even if I rerun the app, it works just as well. However, when I delete the app and reinstall it, I get a Token Expired error and CloudKit doesn't work properly.

My code is organized like this


    public lazy var modelContext: ModelContext = { ModelContext(modelContainer) }()

    private lazy var modelContainer: ModelContainer = {

        let schema = Schema([

            Entity1.self,

            Entity2.self,

            Entity3.self,

        ])

        let modelConfiguration = ModelConfiguration(

            schema: schema,

            groupContainer: .identifier("myGroupContainer"),

            cloudKitDatabase: .automatic

        )

        do {

            return try ModelContainer(for: schema, configurations: [modelConfiguration])

        } catch {

            fatalError("Could not create ModelContainer: \(error)")

        }

    }()

The error content is as follows

error: CoreData+CloudKit: -[PFCloudKitImportRecordsWorkItem fetchOperationFinishedWithError:completion:]_block_invoke(707): <PFCloudKitImporterZoneChangedWorkItem: 0x3022c0000 - <NSCloudKitMirroringImportRequest: 0x3036e7ac0> 1A7E53D4-E95B-423F-8887-66360F6D8865> {
(
    "<CKRecordZoneID: 0x301bb1bf0; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>"
)
} - Fetch finished with error:
<CKError 0x301bb5650: "Partial Failure" (2/1011); "Couldn't fetch some items when fetching changes"; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A; container ID = "MyContainerID"; partial errors: {
	com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x301bb1830: "Change Token Expired" (21/2026); server message = "client knowledge differs from server knowledge"; op = 515034AC3ADC4348; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A>
}>
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1390): <PFCloudKitImporter: 0x3000a1240>: Import failed with error:
<CKError 0x301bb5650: "Partial Failure" (2/1011); "Couldn't fetch some items when fetching changes"; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A; container ID = "MyContainerID"; partial errors: {
	com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x301bb1830: "Change Token Expired" (21/2026); server message = "client knowledge differs from server knowledge"; op = 515034AC3ADC4348; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A>
}>

Forcing the ModelContainer to be reinitialized fixes the problem,

  1. it's a problem to get this error in the first place,
  2. the error doesn't even go to fatal for me, so I don't even know how to verify that it's happening.

Is there something I'm doing wrong, or do you have any good ideas for solving the same problem?

Answered by DTS Engineer in 788547022

The code doesn't seem to have any obvious issue. When detecting an invalid token, which happens when the app is deleted and then re-installed, the system is supposed to schedule an initial synchronization, which downloads the data from the CloudKit database and transforms it to the SwiftData store. The process may take a while depending on the size of the data set. If you don't see that happening, consider filing a feedback report.

In your case, the store locates in the App Group container, which may add a bit more complexity because when your app is removed, the store may still be there if other apps or extensions that use the container still exist. You can try not using the App Group container, and verify if the issue is still there.

The code doesn't seem to have any obvious issue. When detecting an invalid token, which happens when the app is deleted and then re-installed, the system is supposed to schedule an initial synchronization, which downloads the data from the CloudKit database and transforms it to the SwiftData store. The process may take a while depending on the size of the data set. If you don't see that happening, consider filing a feedback report.

In your case, the store locates in the App Group container, which may add a bit more complexity because when your app is removed, the store may still be there if other apps or extensions that use the container still exist. You can try not using the App Group container, and verify if the issue is still there.

I'm having this exact same issue and just can't get it fixed. Identical error message to what is posted above. And I'm not creating a ModelConfiguration or group container as above. This issue just started happening suddenly after my app has been in the appstore for 2.5 months. And now customers are complaining. Desperate to find a solution.

I'm still experiencing this issue. Was hoping it was fixed with iOS18 but I'm still getting the "Change token expired" messages when reinstalling from the app store after deleting the app. Strangely, I see the error messages when deleting the app and installing from Xcode, but several seconds later it will eventually do the iCloud sync. But when just installing from the app store again it will never complete and fail. Can't figure out how to detect when this is happening and how to force an iCloud sync. I understand it's supposed to be automatic but not working that way.

@deokhwa.lee hey I was hoping you could share how you resolved this issue. When you said "Forcing the ModelContainer to be reinitialized fixes the problem".. can you please explain how you do a force reinitialization of the ModelContainer? I've tried everything and can't get that workaround to work. I'm desperate to figure this out as I have frustrated customers waiting. Would be very grateful to you, thanks.

Hi

It has been 4 days for me researching, reading, studying and trying to find a solution for this issue or at least Similar, that I am facing or better said I was facing ...

My issue: I have an application that is already on production and it uses only CoreData, I wanted to go to the next step and include CloudKit to the app, so the user can use it on multiple devices or even after they delete the app they can see and check their old process, I wanted to sustain the data the user saved for them.

I changed the NSPersistentContainer to NSPersistentCloudContainer, added the needed Capabilities, sat the merge policy and assigned the automaticallyMergesChangesFromParent to true.

during testing the app started and everything did migrate I can see it on the dashboard.

the issue was every time I install the app on a different device I never got the entries fetched from iCloud though I can see for that particular user there are entries in my Dashboard.

so the app would generate new entries and sync them to cloud, then after I run the app on that device again, I get the old entries and the new ones that were just added.

How I solved it:

The Idea, the iCloud somehow for the first run is not really synced so I added a function that force sync the cloud before the app starts (in sceneDelegate scene willConnectTo or AppDelegate didFinishLaunchingWithOptions)

what the function does.

I first initialise a CKContainer and get hold of the privateCloudDatabase , as per default the NSPersistentCloudContainer uses the private cloud to save data, unless told otherwise.

then I make a CKQuery to get hold of entries that are in the cloud if there are some.

if I got to know that there are entries in the cloud:

  1. I save a flag to inform later my VM in my VC that yes there are entries in the cloud or there are not.
  2. I initialise a dummy entry save it to my context and then directly delete it (there I made sure that the sync has happened).

this method is an asynchronous/await function, so I wait for it before I start the app.

after this the app starts and I have the information I need to either start the app with really new entries (so I initiate the new entries and sync them) or if the user have a newly installed app but used before I inform the user with an alert asking them to either start the app as a fresh start or migrate the iCloud content to the new app. if the user selects to indeed migrate, then I start the fetch process and I get all the old entries from iCloud.

So What I did is to make sure there is a hand-shake happening to the Cloud.

I hope this helps all who are facing similar issues.

Cheers,

Mohd

CloudKit data is lost when reinstalling the app
 
 
Q