ITMS-91054, ITMS-91055 and ITMS-91056
These three are the "you declared something, but wrong" errors, as distinct from ITMS-91053 which is "you declared nothing" and ITMS-91061 which is "this framework has no manifest at all."
| Code | Means | Usual cause |
|---|---|---|
| ITMS-91054 | Invalid API category declaration | A display label was used where a key string was required |
| ITMS-91055 | Invalid API reason declaration | A reason code that is not valid for that category |
| ITMS-91056 | Invalid privacy manifest | The file will not parse — malformed XML or wrong structure |
All three name a file path, which is the useful part and the part people skim past. Unlike 91053, you are not hunting through 800 packages — the message tells you which file to open.
ITMS-91054 — invalid API category declaration
The error quotes the offending value. A representative message reads that the PrivacyInfo.xcprivacy for a given framework "contains 'Disk Space' as the value for a NSPrivacyAccessedAPIType key, which is invalid."
That is the entire bug: Disk Space is the label Xcode displays; the value Apple's tooling requires is the key string. Xcode's property-list editor renders friendly names for known keys, and if you type or paste what you can see rather than the raw key, you produce a file that looks correct in the editor and fails at upload.
There are exactly five valid values:
NSPrivacyAccessedAPICategoryFileTimestamp
NSPrivacyAccessedAPICategorySystemBootTime
NSPrivacyAccessedAPICategoryDiskSpace
NSPrivacyAccessedAPICategoryActiveKeyboards
NSPrivacyAccessedAPICategoryUserDefaultsNothing else is accepted. Not UserDefaults, not User Defaults, not NSUserDefaults, not NSPrivacyAccessedAPICategoryUserDefault singular.
To see what is really in the file, read it as raw XML rather than in Xcode's editor:
plutil -convert xml1 -o - path/to/PrivacyInfo.xcprivacyITMS-91055 — invalid API reason declaration
The category is valid; the reason code inside NSPrivacyAccessedAPITypeReasons is not one Apple accepts for that category. Reason codes are category-specific and are not interchangeable — CA92.1 is a UserDefaults reason and means nothing under DiskSpace.
The three ways this happens:
A code copied from the wrong category. Usually from a blog post covering a different one.
A code that has drifted. Apple states it "continually reviews the list of required reason APIs and reasons for usage, and will update this article from time to time." A code that was valid when a tutorial was written may not be now.
A code from an incorrect secondary source. Apple's documentation renders client-side, so a plain HTTP fetch of it returns an empty page. That is precisely why wrong copies of the reason-code table circulate — the people compiling them could not read the original either.
We transcribed the complete list in a real browser on 6 September 2026, with dates, for this reason: every category and every valid reason code.
ITMS-91056 — invalid privacy manifest
The file will not parse or is structurally wrong. The message names a path.
Most common causes, in order:
- Malformed XML. An unclosed tag, a stray character, a truncated file from a bad merge.
- Wrong root type. The root must be a dictionary.
- Keys at the wrong nesting level.
NSPrivacyAccessedAPITypeReasonsmust sit inside each dictionary in theNSPrivacyAccessedAPITypesarray, not beside the array. - Wrong value types.
NSPrivacyAccessedAPITypesis an array of dictionaries;NSPrivacyAccessedAPITypeReasonsis an array of strings. A bare string where an array is expected fails. - A merge conflict marker left in the file. It happens more often than anyone admits.
Validate before you upload — this costs one second:
plutil -lint ios/YourApp/PrivacyInfo.xcprivacy
find . -name "PrivacyInfo.xcprivacy" -not -path "*/node_modules/.cache/*" -exec plutil -lint {} \;A structurally correct manifest
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
</dict>
</plist>Those two entries — CA92.1 for UserDefaults and C617.1 for file timestamps in your own container — are the normal, accurate declarations for an ordinary React Native app. They are not a template to paste without checking: declare only what your app actually does, because Apple's terms bind you to the declared reason and several codes carry conditions such as not sending the data off-device.
The Expo trap that makes this recur
With continuous native generation, ios/ is regenerated from app config and config plugins on every prebuild. Fix the manifest in ios/YourApp/PrivacyInfo.xcprivacy, verify locally, push, and EAS overwrites it — same error, second cycle, and the change was correct both times.
Express it in app.json / app.config.js or a config plugin so it survives. Why RN and Expo fail differently.
Catching all three before you build
Every one of these is a static, local, deterministic check: lint every manifest in the tree, validate every category string against the five valid keys, and validate every reason code against the set Apple accepts for its category. None of it needs a build, an upload or a review queue.
That is part of what shipcheck runs, inside the Claude Code session you already have open, against local files. What it checks.
Questions and answers
What is ITMS-91054?
Invalid API category declaration. A PrivacyInfo.xcprivacy file contains a value for NSPrivacyAccessedAPIType that is not one of Apple's five valid category strings. The email names the file and quotes the invalid value - for example that a file "contains Disk Space as the value for a NSPrivacyAccessedAPIType key, which is invalid".
What is ITMS-91055?
Invalid API reason declaration. The category string is valid but the reason code inside NSPrivacyAccessedAPITypeReasons is not one Apple accepts for that category. Reason codes are category-specific and are not interchangeable.
What is ITMS-91056?
Invalid privacy manifest. The PrivacyInfo.xcprivacy file at a given path could not be parsed or is structurally wrong - malformed XML, wrong root type, or keys at the wrong level. The message names the path, which is the most useful part of it.
What is the difference between ITMS-91053 and ITMS-91054?
ITMS-91053 means a required reason API is used and nothing is declared for it. ITMS-91054 means something is declared but the category string itself is invalid. The first is an omission, the second is a typo or a human-readable label used where a key was expected.
Why does my privacy manifest say Disk Space is invalid?
Because the value must be the key string NSPrivacyAccessedAPICategoryDiskSpace, not the display name Xcode shows you. Xcode's plist editor renders friendly labels, and if you copy what you see rather than the raw key, App Store Connect rejects it.
shipcheck. “ITMS-91054, ITMS-91055 and ITMS-91056.” Baker Ventures LLC, September 6, 2026. https://shipcheck.bakerventuresstudio.com/rejections/itms-91054-91055-91056-invalid-privacy-manifest/