You uploaded an iOS build through Xcode or Transporter, the upload finished, and within minutes App Store Connect bounced the binary with ERROR ITMS-91056: Invalid privacy manifest. The rejection email names a specific PrivacyInfo.xcprivacy file path, usually buried inside a third-party framework, and warns that keys and values in the manifest must be valid. This page covers how to read the path fragment, how to validate the file with plutil in the terminal, and how to fix the invalid keys without breaking the rest of the manifest.
Short answer
ITMS-91056 fires when the App Store transporter parses a PrivacyInfo.xcprivacy file and finds a key or value that does not match Apple's documented schema. The fastest diagnostic is plutil -lint to confirm the file is a valid plist, then plutil -p to print its contents in a readable tree. plutil only validates syntax, so semantic errors like duplicate API categories or unknown reason codes still need a manual cross-check against Apple's privacy manifest files documentation. The path fragment in the rejection email names exactly one file. That is the file to fix.
What you should know
- The rejection email names the exact framework. The path fragment after
the file from the following path is invalidpoints at one PrivacyInfo.xcprivacy file insideFrameworks/, not at every manifest in the build. - plutil -lint validates plist syntax only. It confirms the XML or binary plist parses cleanly. It does not check whether the keys or reason codes you used are part of Apple's published schema.
- Enforcement began May 1, 2024. Apple's privacy manifest enforcement window opened that date for new uploads and updates, per Apple's documentation on adding a privacy manifest.
- Third-party SDKs are the most common culprit. The manifest inside an outdated framework usually carries the duplicate-key or unknown-reason-code problem, not your own app's manifest.
- Whitespace and case matter. An extra space inside a string value, or a typo in a key name, will fail Apple's parser even when the plist itself is syntactically valid.
- There is no official validator for semantic content. Apple's TN3181 is the canonical reference; checking is currently a manual diff between your file and the documented schema.
What does the ITMS-91056 path fragment actually point to?
The path fragment after The PrivacyInfo.xcprivacy file from the following path is invalid identifies one file, by exact path, inside your build. The format is typically Frameworks/SomeSDK.framework/PrivacyInfo.xcprivacy or Frameworks/SomeSDK.framework/SomeBundle.bundle/PrivacyInfo.xcprivacy. That single path is the only file the transporter rejected on this pass, and Apple does not list every invalid manifest in one rejection. If your build carries five broken manifests, you will see five separate ITMS-91056 rejections across five separate uploads.
Save the email before you delete it. App Store Connect does not surface the same diagnostic in the build's status view, and the path fragment is the entire piece of state Apple gives you about the failure. The rejection email also implies the framework's source: a CocoaPod under Pods/, a Swift Package under SourcePackages/, an XCFramework dropped into the project, or a manifest inside a sub-bundle. Each source has a different fix path, and identifying the source before touching anything saves an upload cycle.
A path that points at Payload/YourApp.app/PrivacyInfo.xcprivacy (no Frameworks/ segment) is the rarer case where your own app's manifest is the problem. That usually means a hand-edited file with a typo, a duplicated dictionary entry, or a manifest copied from another project with leftover keys.
How do you run plutil -lint and what does it actually catch?
plutil ships with the macOS command line tools and lives at /usr/bin/plutil. Two commands cover the diagnostic. The first checks that the file parses as a valid property list:
plutil -lint PrivacyInfo.xcprivacy
A clean run prints the single line PrivacyInfo.xcprivacy: OK. Any other output, such as Error Reading File or a line and column-numbered parse error, is a syntax failure: a missing closing tag, an unescaped character inside a string, or a corrupted binary plist header. Fix that first; nothing else matters until plist syntax is clean.
The second command prints the parsed contents in a readable tree, which is the form you compare against Apple's documented schema:
plutil -p PrivacyInfo.xcprivacy
The output looks like a JSON-style dictionary, with each top-level key on its own line and arrays expanded inline. According to the response from Apple's DTS engineer in the developer forums thread on validating privacy manifests, plutil -lint catches plist syntax, not semantics. A file can pass plutil -lint cleanly and still fail ITMS-91056 because the keys or values inside it are not on Apple's accepted list. The rejection email's wording, "keys and values must be valid," refers to that semantic layer, not plist syntax.
Which keys and values does Apple accept in PrivacyInfo.xcprivacy?
Apple's privacy manifest files documentation lists four top-level keys, and the App Store transporter rejects anything else.
| Top-level key | Type | What it declares |
|---|---|---|
NSPrivacyTracking | Boolean | Whether the app or SDK engages in tracking under the App Tracking Transparency definition |
NSPrivacyTrackingDomains | Array of strings | Internet domains the app contacts for tracking |
NSPrivacyCollectedDataTypes | Array of dictionaries | Categories of data the app or SDK collects, mapped to use cases and linkage flags |
NSPrivacyAccessedAPITypes | Array of dictionaries | Required Reason APIs the app or SDK calls, each with a reason code from Apple's published list |
Each dictionary under NSPrivacyAccessedAPITypes carries two required keys: NSPrivacyAccessedAPIType (a string from a fixed list, such as NSPrivacyAccessedAPICategoryUserDefaults or NSPrivacyAccessedAPICategoryDiskSpace) and NSPrivacyAccessedAPITypeReasons (an array of reason code strings, such as CA92.1 or E174.1). A typo in either string fails the transporter check.
Each dictionary under NSPrivacyCollectedDataTypes carries four required keys: NSPrivacyCollectedDataType, NSPrivacyCollectedDataTypeLinked, NSPrivacyCollectedDataTypeTracking, and NSPrivacyCollectedDataTypePurposes. Misspelling any of them or supplying a purpose code outside Apple's list is a typical ITMS-91056 trigger.
How do you fix a broken third-party framework manifest?
The fix path depends on who owns the manifest. If you wrote the manifest yourself for your own app, open PrivacyInfo.xcprivacy in Xcode's property list editor (right-click, Open As, Source Code to see the raw XML), remove duplicate dictionary entries, replace any unknown reason code with one from Apple's published list, and re-archive. If the manifest belongs to a third-party SDK, three options are open, in order of preference:
- Update the SDK. Most maintained SDKs have shipped corrected manifests since the May 2024 enforcement window opened. Check the SDK's release notes for any version tagged with a privacy manifest fix, and bump to that version in your Podfile, Package.swift, or Cartfile.
- Open an issue against the SDK repository. If no fixed version exists, the project maintainers usually respond within days; the GitHub issues against frameworks like Reachability.swift and the Mapbox iOS SDK showed turnaround in under a week for ITMS-91056 reports. Reference the exact path fragment from the rejection email so the maintainer can reproduce.
- Patch the manifest locally as a last resort. Edit the manifest inside the framework, then re-sign the framework with
codesignso the bundle seal stays valid. This breaks on the nextpod install, so add a post-install script or fork the SDK if you need the fix to stick.
PTKD.com (https://ptkd.com) sees the patch path frequently in builds shipped by no-code platforms where the wrapper bundles an older SDK and the developer cannot bump versions independently. The cleaner long-term fix is still to push the SDK maintainer to publish a corrected manifest, because a local patch silently regresses on the next dependency update.
What does plutil miss that App Store Connect catches?
Three classes of error pass plutil -lint cleanly and still trigger ITMS-91056.
First, unknown reason codes. plutil treats the string CA92.1 the same as the string CA92.99: both are valid plist strings, so plutil -lint returns OK. Apple's transporter checks the string against a fixed allowlist for the matching API type, and rejects anything outside that allowlist. The allowlist is published in Apple's documentation on adding a privacy manifest.
Second, duplicate dictionary entries. The array under NSPrivacyAccessedAPITypes is allowed to contain multiple dictionaries, but each NSPrivacyAccessedAPIType value should appear only once. A manifest that lists NSPrivacyAccessedAPICategoryFileTimestamp twice (a pattern reported on GitHub against several SDKs after the May 2024 enforcement window) parses cleanly through plutil but bounces at the transporter, per the Apple developer forums reference thread on invalid privacy manifest rejections.
Third, extra whitespace inside string values. A space character before or after CA92.1 inside a reason code string field will fail Apple's check while plutil prints the value as if it were correct. The Apple DTS engineer's response in the developer forums thread on privacy manifest validation calls this out as the most common cause of a rejection that survives plutil cleanly.
What to watch out for
The most common myth around ITMS-91056 is that deleting an SDK's PrivacyInfo.xcprivacy file fixes the rejection. It does not. Apple's privacy manifest enforcement applies to SDKs on Apple's published list of privacy-impacting SDKs, and a missing manifest from one of those SDKs triggers a different rejection, ITMS-91065, instead of ITMS-91056. Deleting the file shifts the failure from invalid manifest to missing manifest.
The second pattern to avoid is bumping every framework at once to chase the fix. That usually introduces new breakages unrelated to privacy, and obscures which SDK actually carried the broken manifest. Bump only the SDK named in the path fragment, re-upload, and read the next rejection email if one comes back.
The third pattern is assuming the path fragment names the framework that owns the manifest. The path does not always reflect ownership. A framework can bundle another framework, and a path like Frameworks/Outer.framework/Frameworks/Inner.framework/PrivacyInfo.xcprivacy means the inner framework owns the manifest. The fix lives there, not in the outer one.
Key takeaways
- Read the path fragment in the ITMS-91056 email before running any command. It names one file, by exact path, and the fix lives in that file.
- Run
plutil -lint PrivacyInfo.xcprivacyto confirm the plist parses, thenplutil -p PrivacyInfo.xcprivacyto print the contents for manual comparison against Apple's schema. Neither catches semantic errors, so a cleanplutilrun is not proof the manifest passes the transporter. - Third-party SDKs cause most ITMS-91056 rejections. Bump the SDK named in the path first; only patch the manifest in place as a last resort, and re-sign the framework with
codesignwhen you do. - For builders who want an external read of every PrivacyInfo.xcprivacy file across their compiled IPA before submission, PTKD.com (https://ptkd.com) is one of the platforms that scans the bundle and flags invalid keys or reason codes against Apple's published schema.




