I'm seeing a critical issue where a custom CKRecordZone is consistently deleted server-side when a second iCloud account interacts with a zone-wide CKShare. I've reproduced this 20+ times across two days and have exhausted every client-side fix I can think of. Looking for guidance on what might be going wrong.
Setup
- Container:
iCloud.com.cohencooks(production app on App Store) - Custom
CKRecordZonein owner's private database - Zone-wide
CKShare(recordZoneID:)(iOS 15+ zone sharing) - SwiftData with
ModelConfiguration(cloudKitDatabase: .none)— no automatic CloudKit mirroring - Acceptance via
CKFetchShareMetadataOperation→CKContainer.accept(metadata)(no UICloudSharingController)
Minimal reproduction
// 1. Owner creates zone + share
let zone = CKRecordZone(zoneName: "MyZone")
try await privateDB.save(zone)
let share = CKShare(recordZoneID: zone.zoneID)
share[CKShare.SystemFieldKey.title] = "My Share" as CKRecordValue
share.publicPermission = .readWrite
let (results, _) = try await privateDB.modifyRecords(saving: [share], deleting: [])
// 2. Owner pushes ~500 records to zone — all succeed
// 3. Second user (different iCloud account) accepts share
let metadata = try await container.shareMetadata(for: shareURL)
try await container.accept(metadata)
// 4. Owner's next CKFetchRecordZoneChangesOperation → zoneNotFound (code 26)
// Zone is permanently gone. allRecordZones() confirms deletion.
What I observe
Three distinct failure patterns depending on configuration:
Pattern 1 — publicPermission = .readWrite, no addParticipant:
Zone dies instantly after acceptance. First push notification shows cloudkit.share changed (zone alive), second push notification returns zoneNotFound. The non-owner never successfully wrote anything.
Pattern 2 — publicPermission = .none with explicit addParticipant:
Zone survives acceptance and 2-3 minutes of bidirectional sync (non-owner pulls 578 records, pushes meal plans back). Then a push notification arrives and the zone is gone. This is dramatically better than Pattern 1 but still fails.
Pattern 3 — Container destabilization after repeated testing: After 20+ create/delete cycles in one day, zones die from the owner's own push notifications — no second device involved at all. The container appears to enter an unstable state.
What I've ruled out
publicPermission = .readWrite | Changed to .none + explicit addParticipant | Zone survived longer but still eventually deleted |
| Zone name tombstoning | Tested 6 fresh names never used in this container | All eventually deleted |
| Non-owner writes causing deletion | Gated ALL non-owner push methods (recipe, meal plan, grocery, photo, event) | Zone still deleted |
database.save(share) vs modifyRecords | Switched to modifyRecords(saving:deleting:) | Zone still deleted |
NSPersistentCloudKitContainer interference | Removed all Core Data CloudKit code | Zone still deleted |
| Double share acceptance | Fresh app install, single acceptance only | Zone still deleted |
| Advanced Data Protection | Neither account has ADP enabled | Not the cause |
| Programmatic vs system acceptance | Tested both container.accept() and tapping share link | Zone still deleted |
CloudKit Dashboard
No ZoneDelete operation is visible in the logs. All operations are ZoneFetch, ZoneChanges, RecordQuery, RecordFetch. I do see EphemeralGroup operations targeting the custom zone — not sure what generates those.
Comparison with working apps
I compared my implementation with another app (Spotbook) that uses the exact same zone-wide CKShare(recordZoneID:) pattern with publicPermission = .readWrite and programmatic acceptance — and it works. The main difference is that app uses CKSyncEngine (iOS 17+) rather than raw CKFetchRecordZoneChangesOperation / CKModifyRecordsOperation. Could CKSyncEngine be handling something internally that prevents this issue?
Questions
- Is there a known interaction between zone-wide
CKShare(recordZoneID:)acceptance and zone lifecycle that could cause zone deletion? - Does
CKSyncEnginehandle zone-wide sharing differently than manualCKFetchRecordZoneChangesOperation+CKModifyRecordsOperation? - What generates
EphemeralGroupoperations in CloudKit Dashboard? Could these trigger a zone delete? - After 20+ zone create/delete cycles in a container, is there a server-side rate limit or tombstone mechanism that would destabilize new zones?
- Is the custom programmatic acceptance flow (
CKFetchShareMetadataOperation→container.accept()) fully supported for zone-wide shares, or does it requireUICloudSharingController?
Any guidance would be greatly appreciated. This is blocking multi-user functionality for our app (mesa, a meal planning app on the App Store). Single-user sync works perfectly — the issue only manifests when a second iCloud account is involved.
Environment: iOS 18.4.1, Xcode 16+, Swift, SwiftUI