You uploaded an iOS build through Xcode or Transporter, the upload finished, and App Store Connect bounced the binary within minutes with ERROR ITMS-91056. The rejection email names a specific PrivacyInfo.xcprivacy file path, usually buried inside a third-party framework, and warns that keys and values must be valid. This page covers the key side of that error: what counts as an invalid key, how to find which key your file got wrong, and how to fix it without breaking the framework's code signature.
Short answer
ITMS-91056 fires when the App Store transporter parses a PrivacyInfo.xcprivacy file and finds a key name that is not part of Apple's documented schema. The fastest diagnostic is plutil -lint to confirm the file parses, then plutil -p to print the parsed dictionary tree. plutil only validates plist syntax, so a misspelled key passes locally and still fails server-side. The path fragment in the rejection email names exactly one file. Diff its key names against Apple's privacy manifest files documentation and rewrite the keys that do not match.
What you should know
- Apple recognizes four top-level keys and no others.
NSPrivacyTracking,NSPrivacyTrackingDomains,NSPrivacyCollectedDataTypes,NSPrivacyAccessedAPITypes. Any other key at the top level is rejected. - The most common invalid key is a typo or capitalization slip.
NSPrivacyAccesedAPIType(one 's'),nsPrivacyTracking(lowercase prefix),NSPrivacyAccessedAPITypeReason(missing trailing 's') all read as valid plist strings but fail the schema check. - Sub-key names are case-sensitive and must sit under the correct parent. A key like
NSPrivacyAccessedAPITypeReasonsoutside a dictionary insideNSPrivacyAccessedAPITypesis structurally wrong. - plutil -lint validates syntax only. It returns
OKfor a file whose key names are misspelled, because the file still parses cleanly as a property list. - Apple's enforcement window opened May 1, 2024. Per Apple's documentation on adding a privacy manifest, the schema check now runs on every new upload of an app that lists SDKs on the published list.
- The rejection email isolates the file, not the line. You get the path to the manifest. Finding the specific invalid key is your job, usually with
plutil -pplus a manual diff against the documentation. - Deleting the manifest swaps one ITMS error for another. Removing a third-party framework's PrivacyInfo.xcprivacy turns ITMS-91056 into ITMS-91065 (missing manifest) if the SDK is on Apple's published list.
Which key names does Apple accept in PrivacyInfo.xcprivacy?
The schema is short and the transporter is strict. Anything outside this table fails ITMS-91056 on upload. The four top-level keys are documented in Apple's privacy manifest files reference, and each carries a fixed inner shape.
| Top-level key | Type | Required sub-keys |
|---|---|---|
NSPrivacyTracking | Boolean | none |
NSPrivacyTrackingDomains | Array of strings | none |
NSPrivacyCollectedDataTypes | Array of dictionaries | NSPrivacyCollectedDataType, NSPrivacyCollectedDataTypeLinked, NSPrivacyCollectedDataTypeTracking, NSPrivacyCollectedDataTypePurposes |
NSPrivacyAccessedAPITypes | Array of dictionaries | NSPrivacyAccessedAPIType, NSPrivacyAccessedAPITypeReasons |
Every key in that table is case-sensitive. NSPrivacyAccessedAPIType (singular) is the sub-key inside the dictionary; NSPrivacyAccessedAPITypes (plural) is the array that holds those dictionaries. Reversing them is one of the most common invalid-key mistakes inside hand-edited manifests, because the difference is one letter and both forms read as plausible at a glance.
For NSPrivacyCollectedDataTypes, each entry inside the array is a dictionary that must carry all four sub-keys. Missing one of them fails the schema check with the same ITMS-91056 wording, even though the cause is omission rather than typo. The NSPrivacyCollectedDataType reference lists every accepted value for the type field; everything else is rejected.
How do you read the framework path in the ITMS-91056 rejection email?
The rejection email contains a sentence shaped like this: The PrivacyInfo.xcprivacy file from the following path is invalid: "Frameworks/SomeSDK.framework/PrivacyInfo.xcprivacy". That path is the only piece of state Apple gives you. It points at exactly one file inside your build, never at every broken manifest at once. If your IPA carries three frameworks with invalid keys, you will see three separate ITMS-91056 rejections across three separate uploads.
The path also implies the source of the manifest. A path under Frameworks/SomeSDK.framework/PrivacyInfo.xcprivacy is a CocoaPod, Swift Package, or XCFramework you depend on. A path under Frameworks/SomeSDK.framework/SomeBundle.bundle/PrivacyInfo.xcprivacy is a resource bundle inside that framework, often a Swift module's bundled resources. A path with no Frameworks/ segment, such as Payload/YourApp.app/PrivacyInfo.xcprivacy, points at your own app's manifest, which is the rarer case and usually means a hand-edit went wrong.
Save the email before you delete it. App Store Connect does not surface the same path in the build status view, and once the email is gone, the path is gone with it. According to the Apple DTS engineer in the developer forums thread on ITMS-91056 troubleshooting, the only documented recovery path beyond reading the email is filing a code-level support request with the archive that reproduces the rejection.
What does plutil -lint actually catch in your key list?
plutil ships with the macOS command line tools at /usr/bin/plutil. Two commands cover the diagnostic. The first checks that the file parses as a property list:
plutil -lint PrivacyInfo.xcprivacy
A clean run prints PrivacyInfo.xcprivacy: OK. Anything else, such as a line-and-column parse error, is a syntax problem (a missing closing tag, a corrupted binary plist header, an unescaped character inside a string). Fix that first. Nothing else matters until plist syntax is clean.
The second command prints the parsed dictionary in a readable tree:
plutil -p PrivacyInfo.xcprivacy
The output reads like a JSON dictionary, with each key on its own line. This is the form you compare against Apple's documented key list by hand. Per the response from the Apple DTS engineer in the forum thread on validating privacy manifests, plutil -lint catches plist syntax, not semantics. A file with the key NSPrivacyAccesedAPIType (misspelled, one 's') still parses cleanly as a property list, and plutil -lint returns OK. The transporter is the layer that compares the key string against the published schema. The rejection wording, keys and values must be valid, refers to that schema match, not to plist syntax.
For a quick automated diff, pipe the output of plutil -p through grep for the four legal top-level keys and inspect anything that does not match. A short shell script that walks every PrivacyInfo.xcprivacy inside an unzipped IPA and prints unrecognized keys finds most invalid-key issues in seconds. PTKD.com (https://ptkd.com) automates that diff against Apple's current schema as part of its IPA pre-submission scan, which is one of the cleaner ways to catch a single bad key inside a framework you did not write.
Why do third-party frameworks keep shipping invalid keys?
Three patterns produce most of the invalid-key reports in maintained SDKs. The first is the early-draft holdover. When Apple announced privacy manifests in 2023, some SDK maintainers shipped manifests using key names from an early WWDC slide that did not survive into the final schema. Frameworks that have not been touched since 2023 sometimes still carry those names. The first reported issue against the Mapbox iOS SDK (mapbox/mapbox-maps-ios#2232) tracked exactly this pattern.
The second is the resource bundle confusion. Many SDKs ship as a Foo.framework that contains an internal Foo.bundle for resources. The manifest sometimes lives in the outer framework, sometimes in the inner bundle, sometimes both. When both copies exist and one is stale, the transporter rejects the stale one. The path fragment in your rejection email tells you which.
The third is the manual merge. SDK maintainers who add the manifest by hand instead of generating it through Xcode's App Privacy template are the most likely to introduce a key typo, a wrong-cased prefix, or a sub-key under the wrong parent. The fix is generally a single character change inside the framework's PrivacyInfo.xcprivacy, but you cannot ship that fix in your build until either the maintainer cuts a new version or you patch and re-sign the framework locally.
The Apple developer forums and GitHub issues against named SDKs (Reachability.swift, NewRelic, Mapbox, WalletConnect, Twilio Voice, Braze) document the recurrence of these patterns in detail. Read the GitHub issue tracker against the named framework in your rejection path before reaching for a local patch; the maintainer often has either a fix or a published workaround.
How do you fix the framework manifest without breaking its signature?
The fix path depends on who owns the manifest. If your own app's manifest is the file with the invalid key, open PrivacyInfo.xcprivacy in Xcode (right-click, Open As, Source Code, to see raw XML), rewrite the key name to match the documented schema, and re-archive. There is no signing concern because the binary you ship is re-signed at archive time.
If the manifest belongs to a third-party SDK, three options are open in order of preference:
- Update the SDK to a version that ships a valid manifest. Most maintained SDKs have shipped corrected manifests since the May 1, 2024 enforcement window opened (per Bitrise's writeup on the enforcement timeline). Check the release notes for a version tagged with a privacy manifest fix and bump it in your Podfile,
Package.swift, or Cartfile. - Open or follow an issue on the SDK's GitHub repository. Reference the exact path fragment from your rejection email. Maintainers usually ship a fix within days when the report is concrete and the path is named.
- Patch the manifest locally as a last resort. Edit the manifest inside the framework directory, then re-sign the framework with
codesignso the bundle seal stays valid. The command form iscodesign --force --sign "Apple Distribution: Your Team" Frameworks/SomeSDK.framework. A local patch silently regresses on the nextpod installorswift package update, so add a post-install script, vendor the framework, or fork the SDK if the fix has to stick.
The local patch is genuinely a last resort because it leaves an undocumented divergence between the framework on your machine and the framework everyone else uses. When the underlying SDK ships an update months later, the build can break in a way that is hard to trace. Push the fix upstream when you can.
What to watch out for
The most common mistake after a first ITMS-91056 rejection is to assume every framework in the build is broken. The transporter rejects the first invalid file it finds; you only learn about more after the first one is fixed. Plan for one to three upload cycles when the build carries several outdated frameworks.
A second mistake is treating the rejection as a binary problem. The invalid key inside a third-party framework has nothing to do with your application code. Recompiling, cleaning the build folder, or bumping the iOS deployment target changes nothing about the manifest the transporter is reading.
A third mistake is interpreting an unknown top-level key as a custom-allowed extension. The schema has no extension points. Apple does not document custom keys, and the transporter rejects any top-level key not in the documented four. If a previous developer left a key like CompanyInternalNotes at the top level of the manifest, remove it.
A fourth is reading the wording keys and values must be valid and chasing the value side first. The most common cause of ITMS-91056 in 2025 and 2026 is the key side, not the value side. Check key names against the schema before touching reason codes or purpose strings.
Key takeaways
- The four legal top-level keys are
NSPrivacyTracking,NSPrivacyTrackingDomains,NSPrivacyCollectedDataTypes,NSPrivacyAccessedAPITypes. Anything else fails ITMS-91056. plutil -lintcatches plist syntax. It does not catch invalid key names. Diff every key against Apple's documentation by hand or run an automated schema diff.- The rejection email's path fragment names one file. Save the email; App Store Connect does not surface the same diagnostic anywhere else.
- For builders who want an automated read of every PrivacyInfo.xcprivacy inside their compiled IPA before submitting, including a per-key schema diff, PTKD.com is one of the platforms focused specifically on that pre-submission step. The right tool depends on whether you have the time to run the static analysis yourself and whether the rejection has already happened.
- When a third-party framework owns the broken manifest, the cleanest fix is an SDK update. A local patch with
codesignworks but silently regresses on the next dependency update.




