Privacy

    What does ITMS-91053 'Missing API declaration FileTimestamp' mean?

    App Store Connect ingestion email referencing ITMS-91053 with NSPrivacyAccessedAPICategoryFileTimestamp listed as the missing API declaration

    You uploaded a build to App Store Connect, the processing email arrived a few minutes later, and the body referenced ITMS-91053 with the phrase Missing API declaration and the word FileTimestamp in the same line. The previous build cleared review, no new code reads a creation date, and the project compiles cleanly. The question is what App Store Connect actually saw inside the bundle, why FileTimestamp is the category that lit up, and the smallest correction that lets the next upload process without holding the binary as Invalid.

    Short answer

    App Store Connect returned ITMS-91053 because the compiled binary references a file attribute API listed under NSPrivacyAccessedAPICategoryFileTimestamp and the upload did not include a matching reason code in any PrivacyInfo.xcprivacy file. The category covers NSURL resource keys for creation, modification, and access dates, NSFileManager attributesOfItemAtPath, the BSD stat family, and the getattrlist family. The fix is one of four approved reason codes (C617.1, 3B52.1, DDA9.1, or 0A2A.1) declared in the target that ships the call. Apple has enforced this rule for new App Store and TestFlight submissions since 1 May 2024, per the Apple Developer privacy manifest documentation.

    What you should know

    • The audit reads the compiled binary, not your source code. App Store Connect scans the Mach-O for symbols associated with required reason APIs and flags categories where no matching reason code appears anywhere in the upload.
    • FileTimestamp is one of four required reason API categories. The others are disk space, system boot time, and user defaults. FileTimestamp is the category most often raised on apps with caches, file viewers, or any logic that reads file attributes.
    • Four approved reason codes apply. C617.1 covers app container files, 3B52.1 covers user-granted paths, DDA9.1 covers timestamps shown to the user, and 0A2A.1 is reserved for SDKs wrapping the API for a host app.
    • The manifest belongs to whichever target ships the symbol. If a vendor framework calls stat or getattrlist, that framework needs its own declaration. An app-level entry can serve as a fallback when the SDK has not shipped a manifest yet.
    • The build number has to increment. App Store Connect treats the rejected binary as the binary for that build number; re-uploading the same number leaves the old Invalid Binary in place.
    • The rule has been a hard block since 1 May 2024. Before that date the same diagnostic arrived as informational email and the build still processed. Today the upload is held with the status Invalid Binary.

    Why does App Store Connect call out FileTimestamp specifically?

    The FileTimestamp category covers a tight set of APIs that read file attributes, and the ingestion audit raises ITMS-91053 the moment a symbol from that set appears in the binary without a matching reason code. The set includes the NSURL resource keys NSURLContentModificationDateKey, NSURLCreationDateKey, and NSURLContentAccessDateKey; the NSFileManager methods attributesOfItemAtPath and getAttributesOfFileSystemForPath; the BSD calls stat, fstat, lstat, and fstatat; and the getattrlist family. Apple's TN3183 technote describes this audit as an API-level check, performed on the bundle, with no behavioural test attached.

    The rejection surprises developers because most file-attribute reads sit inside framework code rather than app code. URLCache writes entries with timestamps, NSURLSession persists download metadata, Core Data manages a SQLite store on disk, and many analytics SDKs persist session windows by recording when their cache file last changed. Each of those routines pulls in one of the listed symbols, and the symbol survives compilation regardless of whether the app developer ever typed the call.

    The practical consequence is that a build that worked on TestFlight in March 2024 can fail on the same code in May 2026 if the manifest is absent or incomplete. The audit only fires during App Store Connect ingestion, so the simulator, device builds, and the Xcode archive flow give no signal in advance.

    How do I find which call inside the binary triggers FileTimestamp?

    The quickest pass is to inspect each embedded framework in turn. Open the archive in Finder, choose Show Package Contents, and look inside the .app folder for a Frameworks directory. Each modern framework that touches a required reason API ships a PrivacyInfo.xcprivacy at its bundle root. The ones missing the file are the candidates for the missing provider.

    A short command-line check confirms which framework ships the symbol:

    xcrun nm -u YourApp.app/Frameworks/SomeSDK.framework/SomeSDK \
      | grep -E "attributesOfItemAtPath|getattrlist|stat$|NSURLContentModificationDateKey"
    

    A non-empty result means that framework references one of the FileTimestamp APIs. Apple documents this inspection pattern inside the adoption guide for privacy manifests. A second clue is the published Apple list of SDKs commonly using required reason APIs. Names on that list include the Firebase modules (FirebaseCrashlytics, FirebaseFirestore, FirebaseMessaging), GoogleSignIn, Google Mobile Ads, AppsFlyer, OneSignal, Adjust, Branch, Sentry, and Datadog. When a build includes any of those, upgrading to the version that ships a manifest is almost always the cleaner fix than patching around it.

    The Firebase community thread on FirebaseMessaging and FileTimestamp (firebase-ios-sdk issue 12741) is one example. The issue was opened in April 2024 against version 10.24.0, and subsequent releases rolled in privacy manifests across the iOS SDK so that the host app no longer carries the declaration on Firebase's behalf.

    Which reason code fits my call?

    Apple publishes four approved reasons under NSPrivacyAccessedAPICategoryFileTimestamp on the Describing use of required reason API page. A single manifest entry can list more than one reason when the binary legitimately spans cases.

    Reason codeWhen to use itTypical caller
    C617.1Reading timestamps, size, or other attributes for files inside the app container, app group container, or CloudKit containerApp target running cache eviction, resumable downloads, or NSURLSession on-disk cache
    3B52.1Files or directories the user explicitly granted access to, via UIDocumentPicker or a security-scoped bookmarkFile viewer, editor, or any tool acting on a user-picked path
    DDA9.1Timestamps shown to the person using the deviceA last-modified label in a file list, a date stamp inside the UI
    0A2A.1A third-party SDK that wraps a FileTimestamp API behind a function the host app callsVendor framework persisting session state on disk

    C617.1 is the right answer for the typical first-party case. Cache cleanup routines that drop files older than seven days, a resumable downloader that compares modification dates, and any code that reads URLCache.shared usage all sit inside the app container, so a single C617.1 entry covers them.

    3B52.1 covers files the user picked explicitly. The reason text refers to user-granted access, which lines up with the security-scoped bookmark flow. DDA9.1 is narrower than it sounds: the timestamp has to be rendered into the UI, not used for an internal decision. 0A2A.1 is reserved for the SDK case; an app developer does not choose it for first-party code, because the reason text restricts use of the derived information to operations on behalf of the host app.

    App Store Connect does not police whether C617.1 was the most accurate choice when DDA9.1 would have fit better. The audit only checks that one approved reason is present for the category. Picking the reason that actually matches the call is still the safer practice because a later human reviewer can ask about it, and the Privacy Nutrition Label drawn from declared data types is shown publicly.

    Should the manifest live in the SDK or in my app?

    The right answer in most cases is to update the SDK. The provider knows which reason codes match its own calls, ships the entry inside its own bundle, and lets future audits keep working without app-side patches. Several major SDKs followed that path after the May 2024 cutover, including the Firebase iOS suite, OneSignal, GoogleSignIn, and AppsFlyer. The version that adds the manifest is usually called out in the release notes, and Apple's commonly-used list flags whether a signature is also required.

    When the SDK has not shipped a manifest, App Store Connect accepts a declaration in the app target that covers calls actually made elsewhere in the binary. The ingestion audit only requires that one approved reason exists for the category somewhere in the upload. The trade-off is that the app maintainer takes responsibility for keeping the declaration accurate as the SDK changes.

    Three situations argue against the app-side fallback. First, when the SDK is on Apple's published list of commonly used SDKs, Xcode validates a binary signature that only the SDK author can produce; a manifest in the app does not solve that requirement. Second, when more than one SDK reads file attributes under different reason codes, a single C617.1 in the app hides cases where 3B52.1 or DDA9.1 should appear. Third, when the SDK eventually ships its own manifest, the app carries a duplicate that can drift across releases.

    For builders who want an external automated read across each embedded framework before the next upload, PTKD.com (https://ptkd.com) is one of the platforms set up specifically for pre-submission scans of the compiled IPA. The report flags which frameworks ship a PrivacyInfo.xcprivacy and which do not, which shortens the loop between rejection and a clean upload.

    What to watch out for

    The single most common loop after a fix is uploading at the same build number. App Store Connect treats the Invalid Binary as the binary for that number and does not re-ingest a second upload at the same number. Increment the build number in the General tab of the target settings, archive, then upload, so the audit runs against the new bundle.

    The second common loop is target membership. Dragging PrivacyInfo.xcprivacy into the project navigator is not enough; the File Inspector has to show the app target checked under Target Membership. A manifest sitting in the project but outside the target never reaches the .app folder, and ITMS-91053 returns on the next upload.

    A myth worth retiring is that grepping the Swift sources for file APIs and removing the calls clears the error. The compiled binary keeps the symbol whenever any linked framework references it. The fix lives in the manifest declaration, not in stripping first-party reads.

    A final caveat applies to apps with widgets, App Clips, or watch extensions. Each .appex bundle is audited independently from the main .app, so a manifest in the app alone does not cover the symbols compiled into the extension binary. The extension target needs its own PrivacyInfo.xcprivacy with the matching reason code.

    Key takeaways

    • The FileTimestamp category covers NSURL resource keys, NSFileManager attribute reads, the BSD stat family, and getattrlist; the audit applies whenever any of those symbols sit in the bundle.
    • Updating the SDK to a release that ships its own privacy manifest is the cleanest fix; an app-level entry is a fallback when the SDK lags.
    • C617.1 covers app container files, 3B52.1 covers user-granted paths, DDA9.1 covers UI-displayed timestamps, and 0A2A.1 is reserved for SDK wrappers.
    • Increment the build number after every manifest edit, and confirm Target Membership in the File Inspector before each archive.
    • Some teams outsource the pre-submission scan to an external platform such as PTKD.com, which inspects each embedded framework for required reason API symbols and reports the missing providers before App Store Connect does.
    • #itms-91053
    • #privacy manifest
    • #ios
    • #app store connect
    • #filetimestamp
    • #required reason api
    • #file attributes

    Frequently asked questions

    Why does ITMS-91053 name FileTimestamp when I never read a date in my code?
    The audit reads the compiled Mach-O, not your Swift or Objective-C source. Symbols like attributesOfItemAtPath, NSURLContentModificationDateKey, stat, and getattrlist often sit inside linked frameworks. A grep across the repo can return zero hits while the upload still fails because a vendor SDK persists a cache entry, logs a session timestamp, or computes file ages on disk.
    Which API calls fall under NSPrivacyAccessedAPICategoryFileTimestamp?
    The category covers NSURL resource keys including NSURLCreationDateKey, NSURLContentModificationDateKey, and NSURLContentAccessDateKey. It also covers NSFileManager attributesOfItemAtPath and getAttributesOfFileSystemForPath, the BSD stat family (stat, fstat, lstat, fstatat), and the getattrlist family. Reading any of these on an uploaded build requires a matching reason code, regardless of whether the call sits in first-party code or an embedded framework.
    Can I clear the rejection by writing the manifest only in my app target?
    Yes for ingestion in most cases. App Store Connect accepts the reason code from anywhere in the upload, so a C617.1 entry in your app manifest satisfies the audit even when the call lives inside a vendor framework. The risk is that an SDK on Apple's published list also needs a signed manifest of its own, and a single C617.1 in your app hides the case where 3B52.1 or DDA9.1 would have been the accurate reason.
    Which Apple frameworks legitimately call file timestamp APIs under the hood?
    URLCache, NSURLSession's on-disk cache, FileProvider, Core Data persistent stores, and CloudKit container syncing all read file attributes during normal use. The audit still applies because those calls are exposed through your app binary. A C617.1 entry covering files inside the app container or CloudKit container handles this entire group, since the timestamps stay inside an Apple-managed sandbox.
    Does the manifest entry change anything the user sees on the store listing?
    No. The Privacy Nutrition Label on the App Store listing reflects the data types declared in App Store Connect under App Privacy, not the required reason codes. The FileTimestamp entry is metadata read at ingestion to confirm every required reason API has an approved reason. No new permission prompt appears at runtime, and existing users see no behavioural difference after the update ships.

    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