9

The CKContainer.discoverAllIdentities request always fails in my CloudKit app. It has continually failed over the course of several days.

A simplified version of the code that is failing (which results in the same error) is:

private func getContacts(completion: (([CKUserIdentity]?) -> Void)?) {
    container.status(forApplicationPermission: .userDiscoverability) { [weak self] status, error in
        if let error = error {
            print(error)
        }

        switch status {
        case .granted:
            self?.discover(completion: completion)
        default:
            print("status not granted")
        }
    }
}

private func discover(completion: (([CKUserIdentity]?) -> Void)?) {
    let op = CKDiscoverAllUserIdentitiesOperation()
    op.qualityOfService = .userInitiated
    op.discoverAllUserIdentitiesCompletionBlock = { error in
        if let error = error {
            print(error)
        }
    }
    op.userIdentityDiscoveredBlock = { identity in
        print(identity)
    }
    op.start()
}

It results in an error being passed to the op.discoverAllUserIdentitiesCompletionBlock. The description of the error in the log is:

<CKError 0x1c4a51a60: "Server Rejected Request" (15/2000); server message = "Internal server error"; uuid = F67453B9-712D-4E5E-9335-929123E3C978; container ID = "iCloud.com.huntermaximillionmonk.topdraw">

Previously, this operation would work, but only for certain iCloud users. Now it's not for both of my test users.

Hunter Monk
  • 1,967
  • 1
  • 14
  • 25
  • Facing the same issue, let me know if you have managed to fix it. – user1046037 Sep 20 '17 at 11:22
  • 1
    It's still a problem. I've found that it only occurs on devices that have many contacts. Try running it on a device that has very few contacts (<10) and see if you get the same error. – Hunter Monk Sep 20 '17 at 17:11
  • 1
    That’s a good point will try that ! – user1046037 Sep 20 '17 at 17:15
  • I just tried with 400 contacts and the operation doesn't fail. Something else seems to be problem. I was able to get the discovered contact. – user1046037 Sep 21 '17 at 09:26
  • I just tried with 700 contacts and operation did fail. Doesn't fail for me with 15. If it didn't fail and you have same # of contacts, what else changed? – Hunter Monk Sep 21 '17 at 16:02
  • It all depends on the contents of the contacts. Especially phone numbers can go wrong. I am still in the middle of eliminating wrong contact info. It is painful to do manually. – user1046037 Sep 21 '17 at 16:04
  • I had populated dummy contacts and it works fine. So number of entries is not the issue. The problem seems to be with the invalid phone numbers like special characters in phone numbers or wrong number of digits or wrong country code – user1046037 Sep 21 '17 at 16:06
  • Ok, that's interesting. Invalid characters in the particular contact you're expecting to be returned, or invalid characters in any of the contacts uploaded? – Hunter Monk Sep 21 '17 at 16:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155022/discussion-between-hunter-maximillion-monk-and-user1046037). – Hunter Monk Sep 21 '17 at 16:20
  • 3
    This error is a bug in iOS 11. This same code will work fine under iOS 10. I strongly urge that anyone affected by this problem in iOS 11 should file a bug report with Apple. – rmaddy Sep 24 '17 at 03:46
  • Great to know @rmaddy, thanks. – Hunter Monk Sep 25 '17 at 14:24
  • I believe @rmaddy is correct. This bug doesn't appear on iOS 10. – Hunter Monk Sep 30 '17 at 03:28
  • Same here, filing a bug report. I fear they abandoned it. – Dima Deplov Oct 03 '17 at 21:44
  • Looks like it is fixed in iOS 11.2 (Xcode 9.2) based on my testing. I faced this issue in iOS 11.0 – user1046037 Dec 25 '17 at 13:24

3 Answers3

3

Problem:

This was a problem in iOS 11.0

Based on my testing:

This works ok in Xcode 9.2 / iOS 11.2.1 on the device (not simulator)

After resetting the simulator works for the first time, doesn't work subsequently, however on the device it works repeatedly.

Code:

let queue = OperationQueue()

func requestPermissions(for permissions: CKApplicationPermissions,
                        completionHandler: @escaping (CKApplicationPermissionStatus, Error?) -> ()) {
    
    CKContainer.default().requestApplicationPermission(permissions) { status, error in
        
        if let error = error {
            
            print("Error for requesting \(permissions) - \(error)")
        }
        
        let statusMessage : String
        
        switch status {
            
        case .granted:
            statusMessage = "Granted"
        case .denied:
            statusMessage = "Denied"
        case .couldNotComplete:
            statusMessage = "Could not complete"
        case .initialState:
            statusMessage = "Initial state"
        }
        
        print("Permission - \(statusMessage)")
        
        completionHandler(status, error)
    }
}


private func discoverAllUsers() {
    
    let operation = CKDiscoverAllUserIdentitiesOperation()
    
    operation.userIdentityDiscoveredBlock = { userIdentity in
        
        print("userIdentity = \(userIdentity)")
    }
    
    operation.discoverAllUserIdentitiesCompletionBlock = { error in
        
        if let error = error {
            
            print("Discover all users Error: \(error) ")
        }
        else {
            print("Discover all users completed successfully")
        }
    }
    
    queue.addOperation(operation)
}
Community
  • 1
  • 1
user1046037
  • 16,755
  • 12
  • 92
  • 138
  • Interesting, I'm still getting this error on 11.2.1. Do you have a gist you could post that I could test? – Hunter Monk Dec 27 '17 at 17:45
  • After resetting the simulator, works for the first time, subsequent runs don't work. On the device running iOS 11.2.1 works consistently. I have updated my answer. – user1046037 Dec 28 '17 at 00:48
2

Edit:

Apple fixed this issue day after this answer was posted, coincidence?! I don't think so :)


This is not actually the answer to the question, but a fix that helped me to cross over this error. It will require you to change your app UI interaction and add ContactsUI framework to your project, moreover your user will be responsible for selecting a contact with iCloud related email.

Good news is that the method discoverUserIdentity is still works. So, you can use it to get CKUserIdentity from manually selected contact.

func addContact(_ contact:CNContact) {

     var lookUpEmails = [CKUserIdentityLookupInfo]()
     for email in contact.emailAddresses {
         lookUpEmails.append(CKUserIdentityLookupInfo(emailAddress: (email.value as String)))
     }

     let checkUserOperation = CKDiscoverUserIdentitiesOperation()
        
     checkUserOperation.userIdentityLookupInfos = lookUpEmails
        
     checkUserOperation.userIdentityDiscoveredBlock = { [unowned self] (identity, info) -> Void in
         if identity.hasiCloudAccount {
             if let recordID = identity.userRecordID {
                  //do something with discovered user
             }
             checkUserOperation.cancel()
         }
     }
     checkUserOperation.queuePriority = Operation.QueuePriority.high
     CKContainer.default().add(checkUserOperation)
}

It might sound useless, but in my case, it helped me to solve the Server Rejected Request" (15/2000) error, to fix one of the features of my app and continue to use the other feature related code with less efforts than I thought.

I hope someone will find this helpful.

Community
  • 1
  • 1
Dima Deplov
  • 3,688
  • 7
  • 45
  • 77
  • This is nice! Unfortunately as you stated, it doesn't fix the problem of "which of my friends are on this app". – Hunter Monk Nov 15 '17 at 23:24
  • @HunterMaximillionMonk yes it is true. But, you know what you can try? You can try to ask for user contacts and after that, request list of contacts with emails and check their user identities. The identities will be there only for users of your app. (As I understood it). – Dima Deplov Nov 16 '17 at 02:04
  • In iOS 11.2 (Xcode 9.2), discoverability seems to work ok for me. Looks like it is fixed now. I faced this issue earlier in iOS 11.0 – user1046037 Dec 25 '17 at 13:28
  • @user1046037 yes, looks like all worked as expected now. – Dima Deplov Dec 25 '17 at 20:35
  • It would be good to update the answer and state that it is fixed now without the workaround, so that it would be helpful for others. Thanks – user1046037 Dec 25 '17 at 22:17
  • @user1046037 please, reread the second line of my answer, I mentioned this here. Tell me how to improve the post if this line is not noticeable enough. – Dima Deplov Dec 25 '17 at 23:14
  • @user1046037, I think that it's a good alternative. It also solves some other discoverability related problems, but of course it's out of context of the question. And I also think that we can face this problem in the future again. So, I don't think the removing of workaround is a good thing. Feel free to edit my answer above the edit cut line and you always have a downvote button if you disagree. – Dima Deplov Dec 25 '17 at 23:36
0

Just another data point on this that might help with the overall picture. I was still seeing this error on 11.2.5 when I used my own iCloud AppleID (with hundreds of contacts) while running a Test App that called discoverAllIdentitiesWithCompletionHandler. I'd get the dreaded CKError 0x1c0051730: "Server Rejected Request" (15/2000); server message = "Internal server error". When I switched to run the exact same code on my daughters iOS11.2.5 device (with just a handful of contacts) the code worked fine. Leads me to believe there is some rate limiting going on when there are a lot of contacts with iOS11. (P.S. No errors at all running on iOS10)