My iOS app uses Core Data for local data management and NSPersistentCloudKitContainer to sync data with user’s private iCloud storage. The app has been functioning correctly for several years, but recently, some users have started encountering a CKError.partialFailure error when the app attempts to export data to iCloud. Due to the critical nature of export errors, several features in the app have been disabled to prevent potential data duplication.
Core Data Setup:
lazy var container: NSPersistentContainer = {
let container: NSPersistentContainer
if storeType == .inMemory {
// Used by unit tests
container = NSPersistentContainer(name: "models")
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
} else {
container = NSPersistentCloudKitContainer(name: "models")
}
container.loadPersistentStores { [weak self] _, error in
if let error = error {
self?.logger.error("Failed to load persistent store: \(error)")
fatalError()
}
}
return container
}()
lazy var context: NSManagedObjectContext = {
container.viewContext.name = "main"
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.undoManager = nil
container.viewContext.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType)
return container.viewContext
}()
Error Handling:
Following the API documentation on partial failures, I have attempted to log the error’s userInfo property for the CKPartialErrorsByItemIDKey. However, the userInfo object appears to be empty:
guard let ckError = SyncMonitor.shared.lastError as? CKError else {
return
}
logger.error("ckError: \(ckError)")
if ckError.code == CKError.partialFailure {
if let dictionary = ckError.userInfo[CKPartialErrorsByItemIDKey] as? NSDictionary {
for (recordID, error) in dictionary {
logger.error("\(recordID): \(error)")
}
}
}
}
This code results in the following log:
ckError: Error Domain=CKErrorDomain Code=2 "(null)"
CloudKit Logs:
Upon reviewing the CloudKit Console logs, I observed two types of errors: QUOTA_EXCEEDED and BAD_REQUEST, both associated with the “returnedRecordTypes” field showing _pcs_data.
Log 1:
{
"time":"17/08/2024, 19:02:14 UTC",
"database":"PRIVATE",
"zone":"com.apple.coredata.cloudkit.zone",
"userId":<redacted>,
"operationId":"14F4FAE7F4B75973",
"operationType":"RecordSave",
"platform":"iPhone",
"clientOS":"iOS;17.5.x",
"overallStatus":"USER_ERROR",
"error":"QUOTA_EXCEEDED",
"requestId":"12EB47C3-08A9-439B-9560-E38C32EE4643",
"executionTimeMs":"259",
"interfaceType":"NATIVE",
"recordInsertBytes":300418,
"recordInsertCount":25,
"returnedRecordTypes":"_pcs_data"
}
Log 2:
{
"time":"17/08/2024, 18:41:31 UTC",
"database":"PRIVATE",
"zone":"com.apple.coredata.cloudkit.zone",
"userId":<redacted>,
"operationId":"8AC0CDC966F6E903",
"operationType":"RecordSave",
"platform":"iPhone",
"clientOS":"iOS;17.5.x",
"overallStatus":"USER_ERROR",
"error":"BAD_REQUEST",
"requestId":"75AC88E2-BFB7-4A41-977D-8E4067A0F40A",
"executionTimeMs":"283",
"interfaceType":"NATIVE",
"returnedRecordTypes":"_pcs_data"
}
It is worth noting that all RecordSave logs containing my app’s data models in the returnedRecordTypes field have been successful. Additionally, I can confirm that users experiencing this error have ample unused iCloud storage.
Despite extensive research on this topic, I have been unable to find relevant information to resolve this issue. It’s unclear whether this _pcs_data error can be ignored, what kind of quota this error refers to, or where I can find more information about how much space my app has consumed. I would greatly appreciate any help in pointing me in the right direction.