Provisioning profile missing entitlement

My iOS app uses CloudKit key-value storage. I have not updated the app in a few years but it works fine. Since it was last updated, I transferred the app from an old organization to my personal developer account. Now that I'm working on the app again I get an error: Provisioning profile "iOS Team Provisioning Profile: com.company.app" doesn't match the entitlements file's value for the com.apple.developer.ubiquity-kvstore-identifier entitlement.

In the entitlement file, it has $(TeamIdentifierPrefix)$(CFBundleIdentifier) as the value for iCloud Key-Value Store. I've verified the variables resolve as expected. When I parse the provisioning profile there is no entitlement value for key-value storage. What am I getting wrong?

Answered by DTS Engineer in 873763022
I’m going to research this further and get back to you.

I reached out to a colleague about this and they confirmed that my guess was correct. Better yet, they pointed me at App Store Connect Help > Transfer an app > Overview of app transfer > Apps using iCloud, which covers this topic specifically. It says this:

If your app uses any of the following, it will be transferred to the transfer recipient after they accept the app transfer.

  • KVS identifiers associated with the app

which confirms that iCloud key-value store preferences are expected to transfer, and this:

If your app uses iCloud Key-Value Storage (KVS), the full KVS value will be embedded in any new provisioning profiles you create for the transferred app. Update your entitlements plist with the full KVS value in your provisioning profile.

My interpretation of this is that you it’s telling you to do what we’ve done in this thread, that is, set the value in the .entitlements file to match that in the profile, that is, the value with the old Team ID.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I want to start by understanding your goals. The com.apple.developer.ubiquity-kvstore-identifier value starts with your Team ID, and the app’s Team ID changed as part of the app transfer. That means that your new version of the app won’t be able to access settings created by the old version. Is that OK?

If so, we can dig into why Xcode is being snarky. But if it’s not OK — if, for example, you’ve stored critical user data in the iCloud key-value store [1] — then things get more complex.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] This is something I strongly recommend against. The UserDefaults subsystem, and thus the key-value store, is intended for preferences, not critical user data.

It's just preferences stored in the key-value store. So yes, it is acceptable for that data to be lost.

To clarify, I have updated the entitlement value with the correct Team ID.

It's just preferences stored in the key-value store.

Cool.

I have updated the entitlement value with the correct Team ID.

OK. But you shouldn’t need to do that because Xcode should pick up the correct Team ID via the $(TeamIdentifierPrefix) syntax.


As to your main issue, I suspect that Xcode has cached something that’s causing this. In situations like this I generally approach the problem in two ways:

  1. First, I create a new dummy test app, with a new bundle ID and thence a new App ID, to check whether this is working in general.
  2. Once I’ve confirmed that, I then start trying to resolve the issue with my real project.

With regards that second step:

  1. In Signing & Capabilities, make sure that “Automatically manage signing” is enabled, the new team is selected in the Team popup, and that Signing Certificate is set to Development.
  2. Choose Product > Clean Build Folder.
  3. Quit Xcode.
  4. In Finder, navigate to ~/Library/Developer/Xcode/UserData/Provisioning Profiles.
  5. And trash everything in that folder.
  6. Relaunch Xcode and let automatic code signing do its magic.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I've created a dummy test app with the same setup as the real one and signing works. However, after deleting derived data and all provisioning profiles, the real app still cannot sign.

I've created a dummy test app with the same setup as the real one and signing works.

Cool.

after deleting derived data and all provisioning profiles, the real app still cannot sign.

Bummer.

So my next suggestion is that you create a new test project but this time choose the same bundle ID as your main app. If that works, there’s something about your main app’s project setup that’s causing the problem. OTOH, if it fails in the same way, it confirms that this is specific to the code signing setup.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I created a new project with the same bundle id and capabilities. Same error.

OK, so definitely not your project.

If you temporarily remove the iCloud key-value storage capability capability, the app builds, right? If so, look in the build log for an entry like this:

CodeSign …/Test811382.app (in target 'Test811382' from project 'Test811382')
    cd …/Test811382
    
    Signing Identity:     "Apple Development: Quinn Quinn (7XFU7D52S4)"
    Provisioning Profile: "iOS Team Provisioning Profile: com.example.apple-samplecode.Test811382"
                          (5db3ba83-07fb-4780-8ca4-f87de64fd20d)

Note For info on how to get the build log, see Command [something] failed with a nonzero exit code.

The UUID in that entry is the UUID of the provisioning profile that Xcode is using to sign your app. You should find that in ~/Library/Developer/Xcode/UserData/Provisioning Profiles. Now dump the contents of that profile like so:

% security cms -D -i 5db3ba83-07fb-4780-8ca4-f87de64fd20d.mobileprovision | plutil -p -
{
  …
  "Entitlements" => {
    "application-identifier" => "SKMME9E2Y8.com.example.apple-samplecode.Test811382"
    "com.apple.developer.icloud-container-development-container-identifiers" => [
    ]
    "com.apple.developer.icloud-container-identifiers" => [
    ]
    "com.apple.developer.icloud-services" => "*"
    "com.apple.developer.team-identifier" => "SKMME9E2Y8"
    "com.apple.developer.ubiquity-container-identifiers" => [
    ]
    "com.apple.developer.ubiquity-kvstore-identifier" => "SKMME9E2Y8.*"
    "get-task-allow" => true
    "keychain-access-groups" => [
      0 => "SKMME9E2Y8.*"
      1 => "com.apple.token"
    ]
  }
  …
}

What do you see?

If you don’t want to post your real Team ID and bundle ID, feel free to redact those. Just make sure you redact them consistently. To continue the example above, you might replace all instances of SKMME9E2Y8 with TEAM_ID.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, the app builds fine when disabling key-value storage.

Dumping the provisioning profile shows this:

  "Entitlements" => {
    "application-identifier" => "TEAM_ID.com.ORGANIZATION.APP"
    "aps-environment" => "development"
    "com.apple.developer.icloud-container-development-container-identifiers" => [
      0 => "iCloud.ORGANIZATION.APP"
    ]
    "com.apple.developer.icloud-container-environment" => [
      0 => "Production"
      1 => "Development"
    ]
    "com.apple.developer.icloud-container-identifiers" => [
      0 => "iCloud.ORGANIZATION.APP"
    ]
    "com.apple.developer.icloud-services" => "*"
    "com.apple.developer.team-identifier" => "TEAM_ID"
    "com.apple.developer.ubiquity-container-identifiers" => [
      0 => "iCloud.ORGANIZATION.APP"
    ]
    "com.apple.developer.ubiquity-kvstore-identifier" => "OTHER_TEAM_ID.com.ORGANIZATION.APP"
    "com.apple.security.application-groups" => [
      0 => "group.ORGANIZATION"
    ]
    "get-task-allow" => true
    "keychain-access-groups" => [
      0 => "TEAM_ID.*"
      1 => "com.apple.token"
    ]
  }

So it does appear that the old team ID for com.apple.developer.ubiquity-kvstore-identifier.

Well, that’s… I’d say unexpected, but I was starting to think that might be the case given the results of our previous diagnostic tests |-:

Try this:

  1. On the Developer website, navigate to the TEAM_ID.com.ORGANIZATION.APP App ID.
  2. Remove the Cloud capability and save that change.
  3. Create a new test provisioning profile for that App ID and download that.
  4. Go back to the App ID, re-enable the Cloud capability, and save that change.
  5. Create another new test provisioning profile and download that.
  6. Dump the entitlement allowlist in both profiles.

The profile from step 3 should have no com.apple.developer.ubiquity-kvstore-identifier entry, and I’m curious what you see in the profile from step 5.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

You are correct that the profile from step 3 has no entry for key-value storage. However, the profile from step 5 still uses the old team ID.

One thing I realized while looking at this is that I'm still a member of the old team. That team's developer subscription is no longer active but I'm still a member. I almost left it when I realized but decided to only follow the steps you suggested.

Step 3 (iCloud not enabled)

"Entitlements" => {
    "application-identifier" => "TEAM_ID.com.ORGANIZATION.APP"
    "aps-environment" => "production"
    "beta-reports-active" => true
    "com.apple.developer.team-identifier" => "TEAM_ID"
    "com.apple.security.application-groups" => [
        0 => "group.ORGANIZATION"
    ]
    "get-task-allow" => false
    "keychain-access-groups" => [
        0 => "TEAM_ID.*"
        1 => "com.apple.token"
    ]
}

Step 5 (iCloud re-enabled)

"Entitlements" => {
    "application-identifier" => "TEAM_ID.com.ORGANIZATION.APP"
    "aps-environment" => "production"
    "beta-reports-active" => true
    "com.apple.developer.icloud-container-development-container-identifiers" => [
        0 => "iCloud.ORGANIZATION.APP"
    ]
    "com.apple.developer.icloud-container-environment" => [
        0 => "Production"
        1 => "Development"
    ]
    "com.apple.developer.icloud-container-identifiers" => [
        0 => "iCloud.ORGANIZATION.APP"
    ]
    "com.apple.developer.icloud-services" => "*"
    "com.apple.developer.team-identifier" => "TEAM_ID"
    "com.apple.developer.ubiquity-container-identifiers" => [
        0 => "iCloud.ORGANIZATION.APP"
    ]
    "com.apple.developer.ubiquity-kvstore-identifier" => "OTHER_TEAM_ID.com.ORGANIZATION.APP"
    "com.apple.security.application-groups" => [
        0 => "group.ORGANIZATION"
    ]
    "get-task-allow" => false
    "keychain-access-groups" => [
        0 => "TEAM_ID.*"
        1 => "com.apple.token"
    ]
}
the profile from step 5 still uses the old team ID.

Interesting. Again, that’s what I expected given our conversation so far, but it’s kinda weird.

If you claim the entitlement with the old prefix, does that work?

That is, in your test app that has the same bundle ID as your real app, edit the .entitlements file and change the value of the com.apple.developer.ubiquity-kvstore-identifier property from $(TeamIdentifierPrefix)$(CFBundleIdentifier) to OTHER_TEAM_ID$(CFBundleIdentifier).

I think it will, but I’d like to confirm that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

In the test app, OTHER_TEAM_ID.$(CFBundleIdentifier) works. In the real app which includes a widget extension, it only works if the app target uses OTHER_TEAM_ID.$(CFBundleIdentifier) and the widget target uses TEAM_ID.$(CFBundleIdentifier).

In the real app which includes a widget extension …

Yeah, that makes sense [1]. And I take it that you actually need to share iCloud key-value store preferences between the app and the widget?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] For the definition of “sense” that we’re converging on here (-:

I need to verify if key-value store is actually needed in the widget or if that can be limited to the app target.

Assuming the widget does not need key-value store access, can the app target be left using the old team id?

can the app target be left using the old team id?

I believe so.

My best guess is that this is a deliberate choice on our part, so that app transfers don’t result in users losing all their iCloud key-value store preferences (in contrast to, for example, keychain items [1]). However, I’ve never seen the exact behaviour documented anywhere.

I’m going to research this further and get back to you.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] See App ID Prefix Change and Keychain Access.

Provisioning profile missing entitlement
 
 
Q