Privacy

    How do I fix ITMS-91056 invalid privacy manifest ReachabilitySwift?

    App Store Connect ingestion email showing the ITMS-91056 invalid privacy manifest error naming the ReachabilitySwift bundle path inside Reachability.framework

    Your archive uploaded, the ingestion email returned ITMS-91056 with the phrase Invalid privacy manifest, and the body of the email named a file at Frameworks/Reachability.framework/ReachabilitySwift.bundle/PrivacyInfo.xcprivacy. The build sits in the Invalid Binary state. The question is which key or value inside that shipped manifest the audit refused, why the file ended up in your archive in the first place, and the smallest change that gets the next upload to a green ingestion.

    Short answer

    App Store Connect returns ITMS-91056 when a PrivacyInfo.xcprivacy file shipped inside an embedded framework, bundle, or xcframework does not parse against Apple's schema for the four recognised top-level keys: NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, and NSPrivacyAccessedAPITypes. The ingestion email prints the path inside the .app, in this case Frameworks/Reachability.framework/ReachabilitySwift.bundle/PrivacyInfo.xcprivacy. The fix is to pull a fresh release of the framework whose manifest passes validation, swap to a maintained alternative, or drop the dependency. An app-level manifest in the main target cannot override a malformed file nested inside a vendored bundle. Apple's Privacy manifest files reference lists the recognised keys and value types.

    What you should know

    • The audit reads every PrivacyInfo.xcprivacy inside the .app, not only the one in your main target. A manifest nested under a third-party framework or its resource bundle is validated on its own merits.
    • The error message names the path, not the failing key. Identifying which entry the audit refused is a separate plist inspection step run with plutil or PlistBuddy on the file inside the archive.
    • The Reachability name appears on Apple's list of SDKs that must ship a signed privacy manifest. ReachabilitySwift, the Swift port, ships a manifest defensively because of the name match.
    • Only four top-level keys are recognised. NSPrivacyTracking is a Boolean, NSPrivacyTrackingDomains is an array of strings, and NSPrivacyCollectedDataTypes plus NSPrivacyAccessedAPITypes are arrays of dictionaries with a fixed set of inner keys.
    • The framework owner is responsible for the file inside the framework. Updating to a release where the maintainer corrected the manifest is the cleaner answer than patching a vendored copy.
    • The build number must change between uploads. Re-uploading at the same number leaves the Invalid Binary record in place even after the fix lands.

    Why does App Store Connect refuse a manifest the SDK author already shipped?

    App Store Connect parses every PrivacyInfo.xcprivacy in the upload through the same validator and compares each key and value against the schema published in Apple's Privacy manifest files reference. A typo in a key name, an unrecognised enum value under NSPrivacyAccessedAPIType, a category that no longer exists, or a value with the wrong plist type (a string where the schema expects a Boolean) is enough to fail the parse. The audit treats the file as one unit: a single invalid entry fails the whole manifest.

    The mechanism matters because the ingestion email mentions only the path, not the line. The maintainer of Reachability.swift tracked the same pattern in issue 421, where developers reported the ITMS-91056 email naming the ReachabilitySwift.bundle path while their own app target carried a valid manifest. The bundle inside the framework was the file the audit refused, even though the main target was clean.

    There is one more reason the file shows up at all. Apple's list of third-party SDKs that require a signed privacy manifest includes the Reachability name. ReachabilitySwift, the Swift port maintained by Ashley Mills, ships under the SwiftPM product name ReachabilitySwift and the framework name Reachability, so maintainers added a manifest defensively. When that defensive file does not parse, the audit fires on the shipped bundle even though the app developer never wrote a line of it.

    Which keys and values does the audit actually accept?

    The privacy manifest plist root is a dictionary. Only four top-level keys are recognised: NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, and NSPrivacyAccessedAPITypes. Any other key fails validation. The values follow a fixed shape per Apple's reference page.

    Top-level keyTypeNotes
    NSPrivacyTrackingBooleantrue or false. Always present, even when the rest of the manifest is empty.
    NSPrivacyTrackingDomainsArray of stringsDomains contacted for tracking. Empty array is valid when tracking is false.
    NSPrivacyCollectedDataTypesArray of dictionariesEach entry has NSPrivacyCollectedDataType (string), NSPrivacyCollectedDataTypeLinked (Boolean), NSPrivacyCollectedDataTypeTracking (Boolean), and NSPrivacyCollectedDataTypePurposes (array of strings).
    NSPrivacyAccessedAPITypesArray of dictionariesEach entry has NSPrivacyAccessedAPIType (one of the five published category strings) and NSPrivacyAccessedAPITypeReasons (array of approved reason codes for that category).

    The five recognised values for NSPrivacyAccessedAPIType are NSPrivacyAccessedAPICategoryUserDefaults, NSPrivacyAccessedAPICategoryFileTimestamp, NSPrivacyAccessedAPICategorySystemBootTime, NSPrivacyAccessedAPICategoryDiskSpace, and NSPrivacyAccessedAPICategoryActiveKeyboards. A misspelt category (NSPrivacyAccessedAPICategoryUserDefault without the trailing s, for example) is the single most common cause of ITMS-91056 in a vendored manifest. The approved reason codes follow the format four-character.one (CA92.1, 1C8F.1, 35F9.1, and so on) listed on Apple's Describing use of required reason API page.

    To inspect the file the email named, open the archived .app in Finder, navigate to the framework path the email printed, and run plutil against the .xcprivacy file:

    plutil -lint YourApp.app/Frameworks/Reachability.framework/ReachabilitySwift.bundle/PrivacyInfo.xcprivacy
    plutil -p YourApp.app/Frameworks/Reachability.framework/ReachabilitySwift.bundle/PrivacyInfo.xcprivacy
    

    The first command exits non-zero on a structural plist error. The second prints the file in a human-readable form so the offending key or value is visible. A typo in a category string, a top-level key the schema does not list, or a value of the wrong plist type tends to surface in seconds.

    How do I tell which dependency pulled in ReachabilitySwift?

    The bundle path inside the .app names the framework, not the package that links it. ReachabilitySwift sits inside Reachability.framework, and several upstream packages add it as a transitive dependency. A Swift Package Manager project pulls it through Package.resolved; a CocoaPods project records it in Podfile.lock; a Carthage project lists it in Cartfile.resolved.

    The fastest scan is a single grep across the lock files at the project root:

    grep -i reachability Package.resolved Podfile.lock Cartfile.resolved 2>/dev/null
    

    The output names the resolver entry and the version. Common parent packages that surface ReachabilitySwift include the Flutter connectivity_plus plugin, ReactiveSwift extensions, and older networking helpers ported from the Apple sample code. When the parent is a Flutter plugin, the manifest file lives inside the iOS subspec the plugin vendors, so updating the plugin to a release where its own manifest is corrected is the path with the smallest blast radius.

    When the parent is your own project linking ReachabilitySwift directly, the choice is between updating to a tag that ships a fixed manifest, switching to a maintained fork, or replacing the dependency with Apple's NWPathMonitor API on iOS 12 and later. NWPathMonitor covers most cases the older library handled, removes the manifest issue at the source, and aligns with Apple's preferred path for the same functionality.

    What is the smallest fix that clears the Invalid Binary?

    Three changes typically land together. None of them touches the main app manifest.

    1. Update the framework to a release whose manifest validates. Pull the latest tag of the dependency, regenerate the lock file (pod install --repo-update for CocoaPods, xcodebuild -resolvePackageDependencies for SPM), clean the build folder, and archive a fresh build with an incremented build number.
    2. If no release is available yet, replace the file inside the vendored framework with a minimal valid manifest. A two-key plist with NSPrivacyTracking set to false and NSPrivacyTrackingDomains set to an empty array passes the audit when the library does not collect data or call a required reason API. Modifying a vendored framework is a short-term patch; the change has to be reapplied on every clean install until the maintainer ships a correct file upstream.
    3. Bump CFBundleVersion before re-uploading. App Store Connect keys the Invalid Binary record to the build number. Re-uploading at the same number returns the same email even after the underlying file is fixed.

    For builders who want an external automated read across every embedded framework before the next upload, PTKD.com (https://ptkd.com) is one of the platforms that inspects compiled IPA bundles and flags PrivacyInfo.xcprivacy files whose keys, categories, or reason codes fall outside Apple's schema. It surfaces the offending entry before App Store Connect does, which shortens the loop between an Invalid Binary email and a clean ingestion.

    How is ITMS-91056 different from ITMS-91053 and ITMS-91065?

    The three audits share the same enforcement source but report different causes. Keeping them separate saves time on the next iteration.

    CodeWhat the audit refusedTypical fix
    ITMS-91053A symbol on Apple's required reason API list is in the binary, and no manifest declares an approved reason code for the matching category.Add a category and reason code entry to the manifest of whichever target or framework links the symbol.
    ITMS-91056A PrivacyInfo.xcprivacy file inside the upload contains a key or value the schema does not recognise.Replace or patch the malformed manifest, usually inside a third-party framework.
    ITMS-91065A privacy manifest at the named path is present but not signed when Apple's list requires a signature.Update to a release of the framework that ships a signature, or remove the framework.

    ITMS-91053 is fixed by adding a missing entry; ITMS-91056 is fixed by repairing a broken one; ITMS-91065 is fixed by upgrading or removing the framework that should carry a signed file. Mixing them up sends the next iteration into the wrong corner.

    What to watch out for

    A few patterns turn a one-build fix into a multi-day loop.

    • Patching a vendored manifest without pinning the dependency. A clean checkout or fresh pod install overwrites the edit. Pin the version in Podfile or Package.swift and keep a note in the repo so the patch survives the next install.
    • Editing the manifest in the project but not the one inside the archive. The audit reads the file that ends up in the .app, not the one in the source tree. Build, open the archive, and inspect the framework path the email named.
    • Assuming the app-level PrivacyInfo.xcprivacy covers the nested one. It does not. The audit treats each manifest in the upload as its own unit.
    • Treating ITMS-91056 as a signing problem. That is ITMS-91065. ITMS-91056 fires on the contents of the file, not its signature.
    • Re-uploading at the same build number. App Store Connect returns the same error on the cached Invalid Binary record.

    Key takeaways

    • ITMS-91056 fires on the contents of a PrivacyInfo.xcprivacy file, and the email names the path inside the archive that failed the schema check.
    • The ReachabilitySwift bundle path appears because the Reachability name sits on Apple's list of SDKs that must ship a manifest, and several upstream Flutter and Swift packages vendor the framework transitively.
    • The four top-level keys (NSPrivacyTracking, NSPrivacyTrackingDomains, NSPrivacyCollectedDataTypes, NSPrivacyAccessedAPITypes) are fixed; anything else fails the parse.
    • The smallest fix is usually a framework update plus a build-number bump, not a change to the main target manifest.
    • Some teams outsource the pre-submission manifest sweep across every embedded framework to platforms like PTKD.com (https://ptkd.com), which surfaces malformed entries before App Store Connect rejects the upload.
    • #itms-91056
    • #privacy manifest
    • #ios
    • #reachabilityswift
    • #invalid binary
    • #third party sdk
    • #privacyinfo.xcprivacy

    Frequently asked questions

    Why does the ITMS-91056 email arrive when my own app-level PrivacyInfo.xcprivacy is correct?
    The audit reads every PrivacyInfo.xcprivacy file inside the uploaded .app, not only the one in your main target. A correct manifest at the app level cannot override a malformed one nested inside a third-party framework or its resource bundle. The path printed in the email points at the file the validator refused, which is the file you need to repair or replace by updating the framework that ships it.
    How is ITMS-91056 different from ITMS-91065?
    ITMS-91056 fires when keys or values inside a PrivacyInfo.xcprivacy file fail the schema check, while ITMS-91065 fires when a manifest at a path Apple's list requires is present but missing a valid signature. The first is a content problem fixed by editing the file or updating the framework. The second is a signing problem fixed by pulling a release where the maintainer signed the manifest properly.
    Can I edit the PrivacyInfo.xcprivacy file inside a third-party framework directly?
    You can, as a short-term patch. Write a minimal valid plist with NSPrivacyTracking set to false and an empty NSPrivacyTrackingDomains array, drop it in place of the broken file, archive, and re-upload with a new build number. The trade-off is that a clean checkout or fresh dependency install overwrites the edit, so the patch has to be reapplied or the dependency version pinned until the maintainer ships a correct file upstream.
    Does removing ReachabilitySwift always fix the problem?
    Often yes, when nothing else in the project links Reachability.framework. Search Package.resolved, Podfile.lock, and Cartfile.resolved for the framework name. If the only reference comes from one parent package, removing that package removes the manifest from the archive. When several plugins pull it transitively, you have to update each plugin to a release whose vendored copy is repaired, since dropping one parent leaves the others in place.
    Why does the email name ReachabilitySwift specifically?
    The Reachability name appears on Apple's published list of SDKs that must ship a privacy manifest. ReachabilitySwift is the Swift port, distributed as ReachabilitySwift.bundle inside Reachability.framework. The audit prints the path it actually inspected, which is the nested .bundle directory rather than the parent framework name. Several Flutter plugins, including connectivity_plus, vendor a copy, which is why the same path turns up across projects that never linked the framework directly.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free