Hi all, I've contacted Apple about this privately but I wanted to post this publicly too just to see if anyone else is experiencing the same issue. We use CloudKit to store "documents" (we'll call them) for our users. We use it directly, not via CoreData etc but through the lower level APIs.
This has been working great for the last 9 months or so. Since a few days ago we've started receiving reports from users that their data has disappeared without a trace from their app. Obviously this is very serious and severe for us. We keep a local copy of the users data but if CloudKit tells us this data has been deleted we remove that local copy to keep in sync.
Nothing has changed client side in terms of our code, and the only way we can see that could cause this, is a fetch that we perform asking for a list of the users "documents" is returning no rows/results, or possibly returning rows with invalid or missing fields.
We have about 30,000 active users per day (1.5m requests/day) using CloudKit and we have only a handful of reports of this. Again this only started happening this week after 9 months of good service.
Has anyone else noticed anything "strange" lately, fetches returning empty? fields missing? Is anyone at Apple aware of any recent changes to CloudKit? or outages? We're really unsure how or who should handle this and who we can escalate to? Any help appreciated.
We have a workaround/mitigation on the way through review at the moment but this is a really big problem for us if we can't rely on CloudKit to remember users data reliably.
CloudKit
RSS for tagStore structured app and user data in iCloud containers that can be shared by all users of your app using CloudKit.
Posts under CloudKit tag
172 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Running the Apple sample code “Sharing Core Data objects between iCloud users” has presented the following challenge:
After the creation of a CKRecord in a Persistent CloudKit Container private database, the owner then shares it to a participant. All works fine.
Then the Owner wants to stop sharing. That's fine too, although the CKRecord remains within the same shared zone within the owner's private database; it doesn't move back to the private database.
Then the owner wants to delete the CKRecord completely. Deletion of the record works, but evidence of the CKShare within the shared zone still remains inside the owner's private database.
It is clearly visible on the CloudKit dashboard.
Probably doesn’t take up much memory but v messy and not cool.
How to delete this CKShare completely, leaving no trace?
Any ideas would be most gratefully received!
I was hoping for an update of SwiftData which adopted the use of shared and public CloudKit containers, in the same way it does for the private CloudKit container.
So firstly, a big request to any Apple devs reading, for this to be a thing!
Secondly, what would be a sensible way of adding a shared container in CloudKit to an existing app that is already using SwiftData?
Would it be possible to use the new DataStore method to manage CloudKit syncing with a public or shared container?
Am I misunderstanding the expected behavior here, or is there a bug in the behavior of @Attribute(.ephemeral) tagged SwiftData model properties?
The documentation for .ephemeral says "Track changes to this property but do not persist". I started using .ephemeral because @Transient was inhibiting SwiftUI from reacting to changes to the property through @Observable.
I am updating the value of my @Attribute(.ephemeral) property about once a second and I am seeing corresponding console log output showing the property as part of the generated CKRecord object. I then confirmed in the CloudKit dev portal that the .ephemeral property was added to the Record schema and contains real values. The behavior seems as though the .ephemeral property is being completely ignored.
This is observed in a new Xcode project using SwiftData with CloudKit, Xcode 16.2, macOS 15.3.1 and during Build & Run testing on physical devices.
I'm having some issues where only a subset of records appear in CloudKit dashboard after I have saved some records in my iOS app using NSPersistentCloudKitContainer. I have noticed that when I'm running my app using the development environment of my CloudKit container everything works smoothly and is uploaded as expected but when I'm using the production environment only a subset of records are actually uploaded.
I'm pulling my hair on how to debug this. -com.apple.CoreData.CloudKitDebug and -com.apple.CoreData.SQLDebug pukes out too much info in the console for me to pinpoint any issue.
One question I often see on DevForums and in my day DTS job is if a Core Data object managed by NSPersistentCloudKitContainer can be shared with other iCloud users.
The answer is yes but you need to do it using CloudKit API directly because NSPersistentCloudKitContainer doesn’t support CloudKit shared database (CKContainer.sharedCloudDatabase) today.
Assuming you have a Core Data object, let’s say a document, that you’d like to collaborate with your colleagues:
You are the document owner and can use NSPersistentCloudKitContainer to fully manages the document and synchronize it across your devices.
You can grab a CloudKit record associated with your document from NSPersistentCloudKitContainer using record(for:) or recordID(for:), and share it to your colleagues using UICloudSharingController. See our Sharing CloudKit Data with Other iCloud Users - https://developer.apple.com/documentation/cloudkit/sharing_cloudkit_data_with_other_icloud_users sample for how to share a CloudKit record.
After accepting the sharing, your colleague, as a participant, can view or edit the shared document. The document resides in the participant’s CloudKit shared database and you have to manage it with your own code.
When your colleague edits and saves the shared document, the changes go to the owner’s private database, and eventually synchronize to NSPersistentCloudKitContainer on the owner side.
As you can see, you need to implement #2 and #3 with your own code because NSPersistentCloudKitContainer can’t manage the data in the participant's shared database. If you have any difficulty after going through the above sample code, you can contact Apple’s DTS for help.
I just released an App update the didn't touch ANYTHING to do with Core Data (nothing changed in our Coredata code for at least 8 months). The update uses SDK for iOS 18 and Xcode 16.2 and the app now requires iOS 18 and was a minor bug patch and UI improvements for recent iOS changes.
Since the update we are getting a steady trickle of users on iOS 18, some who allow the App to store data in iCloud (Cloudkit) and others who do not, all reporting that after the update to our recent release ALL their data is gone?!
I had not seen this on ANY device until today when I asked a friend who uses the App if they had the issue and it turned out they did, so I hooked their device up to Xcode and ALL the data in the CoreData database was gone?! They are NOT using iCloud. There were no errors or exceptions on Xcode console but a below code returned NO records at all?!
Chart is custom entity and is defined as:
@interface Chart : NSManagedObject {}
let moc = pc.viewContext
let chartsFetch = NSFetchRequest<NSFetchRequestResult>(entityName:"Charts") // Fetch all Charts
do {
let fetchedCharts = try moc.fetch(chartsFetch) as! [Chart]
for chart in fetchedCharts {
....
}
}
A break point inside the do on fetchedCharts show there are NO objects returned.
This is a serious issue and seems like an iOS 18 thing. I saw some people talking in here about NSFetchRequest issues with iOS 18. I need some guidance here from someone Apple engineer here who knows what the status of these NSFetchrequest bugs are and what possible workarounds are. Becasue this problem will grow for me as more users update to iOS 18.
When I try to promote schema to production, I get following error:
Cannot promote schema with empty type 'workspace', please delete the record type before attempting to migrate the schema again
However, in hierarchical root record sharing, I think it should be completely legit use case where there is empty root record (in my case workspace) to which other records reference through ->parent reference.
Am I missing something? Is this weird constraint imposed on CloudKit?
Hello,
I am trying to access my cloudkit database from the icloud developer dashboard but I am getting the following error:
Error looking up Developer Teams
XHR request failure
Please sign out and try again.
I tried signing out but the error persists,
Thanks
I have two recordTypes in CloudKit: Author and Book. The Book records have their parent property set to an Author, enabling hierarchical record sharing (i.e., if an Author record is shared, the participant can see all books associated with that author in their shared database).
When syncing with CKSyncEngine, I was expecting handleFetchedRecordZoneChanges to deliver all Author records before their associated Book records. However, unless I’m missing something, the order appears to be random.
This randomness forces me to handle two codepaths in my app (opposed to just one) to replicate CloudKit references in my local persistency storage:
Book arrives before its Author → I store the Book but defer setting its parent reference until the corresponding Author arrives.
Author arrives before its Books → I can immediately set the parent reference when each Book arrives.
Is there a way to ensure that Author records always arrive before Book records when syncing with CKSyncEngine? Or is this behavior inherently unordered and I have to implement two codepaths?
Hi everyone,
I've recently implemented CKSyncEngine in my app, and I have two questions regarding its behavior:
Duplicate FetchedRecordZoneChanges After Sending Changes:
I’ve noticed that the engine sometimes receives a FetchedRecordZoneChanges event containing modifications and deletions that were just sent by the same device a few moments earlier. This event arrives after the SentRecordZoneChanges event, and both events share the same recordChangeTag, which results in double-handling the record.
Is this expected behavior? I’d like to confirm if this is how CKSyncEngine works or if I might be overlooking something.
Handling Initial Sync with a "Sync Screen":
When a user opens the app for the first time and already has data stored in iCloud, I need to display a "Sync Screen" temporarily to prevent showing partial data or triggering abrupt, rapid UI changes.
I’ve found that canceling current operations, then awaiting sendChanges() and fetchChanges() works well to ensure data is fully synced before dismissing the sync screen:
displaySyncScreen = true
await syncEngine.cancelOperations()
try await syncEngine.sendChanges()
try await syncEngine.fetchChanges()
displaySyncScreen = false
However, I’m unsure if canceling operations like this could lead to data loss or other issues. Is this a safe approach, or would you recommend a better strategy for handling this initial sync state?
Hello,
I'm using CoreData + CloudKit and I am facing the following error 134100 "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
All my schema updates are composed of adding optional attributes to existing entities, adding non-optional attributes (with default value) to existing entities or adding new entities Basically, only things that lightweight migrations can handle.
Every time I update the schema, I add a new model version of xcdatamodel - who only has a single configuration (the "Default" one). And I also deploy the updated CloudKit schema from the dashboard.
It worked up to v3 of my xcdatamodel, but started to crash for a few users at v4 when I added 16 new attributes (in total) to 4 existing entities.
Then again at v5 when I added 2 new optional attributes to 1 existing entity.
I'm using a singleton and here is the code:
private func generateCloudKitContainer() -> NSPersistentCloudKitContainer {
let container = NSPersistentCloudKitContainer(name: "MyAppModel")
let fileLocation = URL(...)
let description = NSPersistentStoreDescription(url: fileLocation)
description.shouldMigrateStoreAutomatically = true
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
let options = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.company.MyApp")
options.databaseScope = .private
description.cloudKitContainerOptions = options
container.persistentStoreDescriptions = [description]
container.viewContext.automaticallyMergesChangesFromParent = true
container.loadPersistentStores { description, error in
container.viewContext.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType)
if let error {
// Error happens here!
}
}
return container
}
I can't reproduce it yet. I don't really understand what could lead to this error.
I have developed an app that I had been testing on the hardware device with the developer profile signed builds, I had setup a CloudKit container in development mode and also had tested with Production mode and they are working as expected. I have also tested storekit auto renewal subscriptions using Storekit Config file and all of that is working on the hardware device with the developer profile signed builds.
Now comes the Fun Part, I want to use the Distribution profile to test the app for production readiness, I had created a distribution profile and had set that up in the Release under target of the app in Xcode, I have also created sandbox tester account (which is showing inactive even after 7 days - though I am also logged in with this sandbox tester account on a hardware device and under developer setting it shows as a sandbox tester account)
All the subscriptions are showing Ready to Submit in the App Store Connect.
I need help understand this whole flow, how to ensure I can test CloudKit and storekit for production readiness and then publish my app for the review.
Thank you.
Topic:
Developer Tools & Services
SubTopic:
General
Tags:
Subscriptions
Developer Tools
CloudKit
StoreKit
Hello everyone,
I'm looking for updated information on CloudKit pricing for both public and private users. Apple provides a free tier, but I couldn't find a clear breakdown of the costs for exceeding the free limits.
Specifically, I would like to know:
Public data storage: What are the costs associated with storing and querying public records?
Private data storage: How is pricing handled when a user's private data exceeds their iCloud quota?
Additional requests and bandwidth: Are there any charges for extra API requests or data transfer beyond the free limits?
If anyone has insights or an official reference, I'd really appreciate your help. Thanks in advance!
I need to know the current date to query CloudKit data with it, like:
let predicate = NSPredicate(format: "publishedAt <= %@", currentDateAndTime)
I don't need high precision, even +/- a few minutes is fine, but I can't rely on device's time since the user can manually change it.
Researching this myself I see that the most reliable method is to get the date from the server.
There are NTP servers, but accessing them requires additional libraries which adds complexity. TrueTime (last updated 6 years ago) and Kronos (updated like once a year) seem outdated, given how much Swift has changed in the past years.
I can make an HTTP request to a website like Google or Apple and read the current time from its headers. But I don't know if this method is reliable.
I know I can create a dummy record in CloudKit, update it, and read its modificationDate. But it feels hacky.
Maybe there is another way to fetch the current date directly from CloudKit?
It feels like it should be easy and there is a straightforward solution, but I just can't find it.
I have a project that currently has data saved locally and I'm trying to get it to sync over multiple devices.
Currently basic data is syncing perfectly fine, but I'm having issues getting the images to convert to data. From what I've researched it because I'm using a UIImage to convert and this caches the image
It works fine when there's only a few images, but if there's several its a pain
The associated code
func updateLocalImages() {
autoreleasepool {
let fetchRequest: NSFetchRequest<Project> = Project.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "converted = %d", false)
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Project.statusOrder?.sortOrder, ascending: true), NSSortDescriptor(keyPath: \Project.name, ascending: true)]
do {
let projects = try viewContext.fetch(fetchRequest)
for project in projects {
currentPicNumber = 0
currentProjectName = project.name ?? "Error loading project"
if let pictures = project.pictures {
projectPicNumber = pictures.count
for pic in pictures {
currentPicNumber = currentPicNumber + 1
let picture : Picture = pic as! Picture
if let imgData = convertImage(picture: picture) {
picture.pictureData = imgData
}
}
project.converted = true
saveContext()
}
}
} catch {
print("Fetch Failed")
}
}
}
func convertImage(picture : Picture)-> Data? {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let path = paths[0]
if let picName = picture.pictureName {
let imagePath = path.appendingPathComponent(picName)
if let uiImage = UIImage(contentsOfFile: imagePath.path) {
if let imageData = uiImage.jpegData(compressionQuality: 0.5) {
return imageData
}
}
}
return nil
}```
I'm using NSPersistentCloudKitContainer to save, edit, and delete items, but it only works half of the time. When I delete an item and terminate the app and repoen, sometimes the item is still there and sometimes it isn't. The operations are simple enough:
moc.delete(thing)
try? moc.save()
Here is my DataController. I'm happy to provide more info as needed
class DataController: ObservableObject {
let container: NSPersistentCloudKitContainer
@Published var moc: NSManagedObjectContext
init() {
container = NSPersistentCloudKitContainer(name: "AppName")
container.loadPersistentStores { description, error in
if let error = error {
print("Core Data failed to load: \(error.localizedDescription)")
}
}
#if DEBUG
do {
try container.initializeCloudKitSchema(options: [])
} catch {
print("Error initializing CloudKit schema: \(error.localizedDescription)")
}
#endif
moc = container.viewContext
}
}
I’m getting a 0xdead10cc crash in a basic CoreData/CloudKit application. I only have one CoreData save call and its made when the app is in the foreground and it's minor so I don't think its being caused by that. My best guess is that it's related to background syncing of CloudKit. Does anyone know how to fix it? I've been advised that adding the following code around any saves will fix it, but it seems weird that this is the solution. I would expect the inner CoreData/CloudKit engine to handle this.
ProcessInfo().performActivity(reason: "Persisting to context") {
// Save to context here
}
Here is the crashing thread
Thread 7:
0 libsystem_kernel.dylib 0x00000001edc086f4 guarded_pwrite_np + 8 (:-1)
1 libsqlite3.dylib 0x00000001ca71b6e4 seekAndWrite + 456 (sqlite3.c:44287)
2 libsqlite3.dylib 0x00000001ca6d5df4 unixWrite + 180 (sqlite3.c:44365)
3 libsqlite3.dylib 0x00000001ca723b90 pagerWalFrames + 872 (sqlite3.c:67093)
4 libsqlite3.dylib 0x00000001ca6d5b14 sqlite3PagerCommitPhaseOne + 316 (sqlite3.c:70409)
5 libsqlite3.dylib 0x00000001ca6c6494 sqlite3BtreeCommitPhaseOne + 172 (sqlite3.c:81106)
6 libsqlite3.dylib 0x00000001ca6c605c vdbeCommit + 1136 (sqlite3.c:94124)
7 libsqlite3.dylib 0x00000001ca69f778 sqlite3VdbeHalt + 1340 (sqlite3.c:94534)
8 libsqlite3.dylib 0x00000001ca6c0618 sqlite3VdbeExec + 42648 (sqlite3.c:103922)
9 libsqlite3.dylib 0x00000001ca6b56c0 sqlite3_step + 960 (sqlite3.c:97886)
10 CoreData 0x00000001a459ab38 _execute + 128 (NSSQLiteConnection.m:4614)
11 CoreData 0x00000001a45fe004 -[NSSQLiteConnection commitTransaction] + 728 (NSSQLiteConnection.m:3278)
12 CoreData 0x00000001a469888c _executeGenerateObjectIDRequest + 388 (NSSQLCore_Functions.m:6021)
13 CoreData 0x00000001a46986a4 -[NSSQLGenerateObjectIDRequestContext executeRequestCore:] + 28 (NSSQLObjectIDRequestContext.m:42)
14 CoreData 0x00000001a45fb380 -[NSSQLStoreRequestContext executeRequestUsingConnection:] + 240 (NSSQLStoreRequestContext.m:183)
15 CoreData 0x00000001a45fb0a8 __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke + 60 (NSSQLConnectionManager.m:307)
16 CoreData 0x00000001a45fafe0 __37-[NSSQLiteConnection performAndWait:]_block_invoke + 48 (NSSQLiteConnection.m:755)
17 libdispatch.dylib 0x00000001a4357fa8 _dispatch_client_callout + 20 (object.m:576)
18 libdispatch.dylib 0x00000001a43677fc _dispatch_lane_barrier_sync_invoke_and_complete + 56 (queue.c:1104)
19 CoreData 0x00000001a45b5ba4 -[NSSQLiteConnection performAndWait:] + 176 (NSSQLiteConnection.m:752)
20 CoreData 0x00000001a45b5a68 -[NSSQLDefaultConnectionManager handleStoreRequest:] + 248 (NSSQLConnectionManager.m:302)
21 CoreData 0x00000001a45b5938 -[NSSQLCoreDispatchManager routeStoreRequest:] + 228 (NSSQLCoreDispatchManager.m:60)
22 CoreData 0x00000001a45b573c -[NSSQLCore dispatchRequest:withRetries:] + 172 (NSSQLCore.m:4044)
23 CoreData 0x00000001a46737b4 -[NSSQLCore _obtainPermanentIDsForObjects:withNotification:error:] + 1324 (NSSQLCore.m:2830)
24 CoreData 0x00000001a460ba98 -[NSSQLCore _prepareForExecuteRequest:withContext:error:] + 272 (NSSQLCore.m:2946)
25 CoreData 0x00000001a460a0f8 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke.547 + 8988 (NSPersistentStoreCoordinator.m:2995)
26 CoreData 0x00000001a45d6660 -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 264 (NSPersistentStoreCoordinator.m:668)
27 CoreData 0x00000001a45ded28 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1200 (NSPersistentStoreCoordinator.m:2810)
28 CoreData 0x00000001a4655988 -[NSManagedObjectContext save:] + 984 (NSManagedObjectContext.m:1593)
29 CoreData 0x00000001a46f47dc __52+[NSCKEvent beginEventForRequest:withMonitor:error:]_block_invoke_2 + 352 (NSCKEvent.m:76)
30 CoreData 0x00000001a45c28f0 developerSubmittedBlockToNSManagedObjectContextPerform + 476 (NSManagedObjectContext.m:3984)
31 libdispatch.dylib 0x00000001a4357fa8 _dispatch_client_callout + 20 (object.m:576)
32 libdispatch.dylib 0x00000001a43677fc _dispatch_lane_barrier_sync_invoke_and_complete + 56 (queue.c:1104)
33 CoreData 0x00000001a4615c34 -[NSManagedObjectContext performBlockAndWait:] + 308 (NSManagedObjectContext.m:4108)
34 CoreData 0x00000001a46f45ac __52+[NSCKEvent beginEventForRequest:withMonitor:error:]_block_invoke + 192 (NSCKEvent.m:66)
35 CoreData 0x00000001a4825e68 -[PFCloudKitStoreMonitor performBlock:] + 92 (PFCloudKitStoreMonitor.m:148)
36 CoreData 0x00000001a46f4394 +[NSCKEvent beginEventForRequest:withMonitor:error:] + 256 (NSCKEvent.m:61)
37 CoreData 0x00000001a47cc6ec __57-[NSCloudKitMirroringDelegate _performExportWithRequest:]_block_invoke + 260 (NSCloudKitMirroringDelegate.m:1433)
38 CoreData 0x00000001a47c9970 __92-[NSCloudKitMirroringDelegate _openTransactionWithLabel:assertionLabel:andExecuteWorkBlock:]_block_invoke + 72 (NSCloudKitMirroringDelegate.m:957)
39 libdispatch.dylib 0x00000001a4356248 _dispatch_call_block_and_release + 32 (init.c:1549)
40 libdispatch.dylib 0x00000001a4357fa8 _dispatch_client_callout + 20 (object.m:576)
41 libdispatch.dylib 0x00000001a435f5cc _dispatch_lane_serial_drain + 768 (queue.c:3934)
42 libdispatch.dylib 0x00000001a4360158 _dispatch_lane_invoke + 432 (queue.c:4025)
43 libdispatch.dylib 0x00000001a436b38c _dispatch_root_queue_drain_deferred_wlh + 288 (queue.c:7193)
44 libdispatch.dylib 0x00000001a436abd8 _dispatch_workloop_worker_thread + 540 (queue.c:6787)
45 libsystem_pthread.dylib 0x0000000227213680 _pthread_wqthread + 288 (pthread.c:2696)
46 libsystem_pthread.dylib 0x0000000227211474 start_wqthread + 8 (:-1)
I'm beta-testing a CloudKit-based app. One of my testers suddenly reported that they got a .badContainer CloudKit error:
<CKError 0x302619800:"Bad Container" (5/1014); server message = "Invalid container to get bundle ids"; op = <...>; uuid = <...>; container ID = "<...>">
(all private info replaced with <...>)
The container ID in the message was exactly what I expected, and exactly what other users are successfully using.
When I followed up on the report, the user said she tried again later and everything was fine. It's still working fine days later.
What could cause a user to get a .badContainer message, when all other users using the same app are fine, the container ID makes sense, and future runs work fine?
Is this something I need to worry about? Does it maybe sometimes happen when CloudKit is having some kind of outage?
My question
Is there a way to perform an iCloud keychain reset in order to be able to test CKErrorUserDidResetEncryptedDataKey ?
I found this section in the CloudKit documentation
https://developer.apple.com/documentation/cloudkit/encrypting-user-data#Handle-a-User-Keychain-Reset
I want to be prepared for the zoneNotFound / CKErrorUserDidResetEncryptedDataKey case.
However, I can't find a way to actually reproduce this error with an iCloud (test-) user and can't find any Apple documentation on how to perform sucha "User Keychain Reset".
The only thing that almost looked like it I came across was in the Keychain.app's Settings "Reset Default Keychains…". However, performing this didn't seem to affect the CloudKit data used in our App at all.
I've been trying to do this with an Apple account that has 2FA active and a recovery account assigned.
We're only targetting >= iOS 18, macOS >= 15.