iOS

    How do I fix ITMS-90338 non-public API usage?

    An App Store Connect ITMS-90338 non-public API usage rejection in 2026 naming a symbol in a bundled framework, next to a terminal running nm to trace the symbol to a legacy ReachabilitySwift dependency

    An ITMS-90338 rejection names a symbol your binary should not be touching, and when it points at something like ReachabilitySwift, the cause is almost never your own code. It is a legacy SDK referencing a private Apple API. The work is to find which library carries the flagged symbol, then update or replace it. Here is how to do both.

    Short answer

    ITMS-90338 means App Store static analysis found your binary referencing a non-public Apple symbol, and the rejection email names the symbol and the framework it sits in. The usual cause is an old or abandoned third-party SDK, such as a dated ReachabilitySwift, rather than code you wrote. Find which library references the symbol with nm or otool, then update or replace that dependency, for example moving from ReachabilitySwift to Apple's Network framework. Because the symbol is compiled into the binary, the fix always ships in a new build.

    What you should know

    • It is a private-API reference: your binary calls or links a symbol Apple does not publish.
    • The email names the symbol: ITMS-90338 lists the exact selector and the framework it was found in.
    • The cause is usually a dependency: a static library or SDK carries the symbol, not your own code.
    • Legacy networking libraries are common offenders: an old ReachabilitySwift is a frequent example.
    • The fix is a new build: the reference is in the binary, so you rebuild after updating or replacing the library.

    What does ITMS-90338 actually mean?

    It means the App Store's automated check found a reference to a non-public Apple selector in your uploaded binary. Apple runs static analysis at upload, looks for symbol names that match its private APIs, and rejects the build with ITMS-90338 when it finds one, listing the symbol and the binary image it lives in. This is not a runtime test or a human review; it is a name-matching scan over the compiled code. The reference can be a genuine call into a private API, or a symbol whose name happens to collide with a private selector, and the email does not tell you which dependency introduced it. The check runs the same way whether the symbol came from Swift, Objective-C, or a precompiled static library, so the rejection looks identical no matter which language or build system produced the binary.

    How do you find which SDK references the symbol?

    Search the compiled binary and its frameworks for the flagged symbol. The command-line tools that ship with Xcode list the symbols a binary references, so you can trace the name in the rejection back to a specific library. Start by dumping undefined external symbols:

    nm -u MyApp.app/Frameworks/ReachabilitySwift.framework/ReachabilitySwift
    

    Then search a binary or framework for the exact symbol the email named:

    nm -Umo MyApp.app/MyApp | grep -i theFlaggedSymbol
    

    The table lists the tools worth knowing.

    CommandWhat it shows
    nm -uThe undefined external symbols a binary references
    nm -UmoEach symbol with the object or library it belongs to
    otool -ovObjective-C class and method structures in the binary
    stringsReadable strings, including symbol names, inside the binary

    Run these against your app binary and each bundled framework until the flagged symbol shows up, and the framework it appears in is the dependency you need to fix.

    How do you fix it once you find it?

    Update the offending library, or replace it. If the SDK has a newer release that renamed or removed the symbol, updating the dependency is the fastest fix. If it is unmaintained, replace it with a supported alternative: for reachability specifically, Apple's Network framework and its NWPathMonitor cover network status without a third-party library, which removes the class of problem entirely. If the flagged symbol is your own method that happens to match a private selector, rename your method. After any of these, rebuild and resubmit, because the reference lives in the compiled binary and only a new build clears it. If you manage dependencies with CocoaPods, Swift Package Manager, or a React Native or Flutter plugin, the update happens at the manifest level, and you regenerate the build so the corrected symbols replace the old ones inside the binary.

    Is it always a real private-API call, or sometimes a false positive?

    It can be either. The check matches symbol names, so a public method or property whose name coincides with a private Apple selector can be flagged even though it never calls a private API. Developers report this kind of collision, and in a genuine false positive you can reply to App Review explaining that the symbol is your own and what it does. The honest caveat is that a reply is slower and less certain than removing the cause, so when the symbol comes from a replaceable dependency, updating or swapping the library is the more reliable path than arguing the false positive. Keep the rejection email either way, because it names the precise symbol you are tracing, and that exact string is what you search for in the steps above.

    What to watch out for

    The trap is the transitive dependency you did not add directly. A private-API symbol can ride in through a library that one of your other libraries depends on, so the offender may not appear in your own dependency list. Scanning the binary is the reliable way to see what is actually linked, rather than what you think you included. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the compiled APK, AAB, or IPA and reports the SDKs and symbols inside it against OWASP MASVS, which is exactly the legacy-SDK identification this rejection demands, so you can catch a forbidden-API reference before the upload does. The limit is that a scan finds the reference; you still decide whether to update, replace, or rename.

    What to take away

    • ITMS-90338 means your binary references a non-public Apple symbol, and the rejection email names the symbol and its framework.
    • The cause is usually a legacy SDK, such as an old ReachabilitySwift, not your own code.
    • Trace the symbol to a library with nm or otool, then update the SDK, replace it (for reachability, use Apple's NWPathMonitor), or rename a colliding method, and rebuild.
    • A binary scan such as PTKD.com identifies which bundled SDK carries a forbidden-API reference, including transitive dependencies, before App Store analysis flags it.
    • #itms-90338
    • #non-public-api
    • #private-api
    • #reachabilityswift
    • #app-store-rejection
    • #static-analysis
    • #ios

    Frequently asked questions

    What does ITMS-90338 mean?
    It means the App Store's automated static analysis found your binary referencing a non-public Apple selector, and rejected the build. The email lists the exact symbol and the framework it was found in. This is a name-matching scan over the compiled code at upload, not a runtime test or human review, so a build with a private-API reference is blocked before review even begins.
    How do I find which SDK is using the private API?
    Search the binary and its frameworks for the flagged symbol with command-line tools. Use nm -u to list undefined external symbols, nm -Umo piped to grep to find the named symbol and its library, and otool -ov to inspect Objective-C methods. Run them against your app binary and each bundled framework until the symbol appears; the framework it shows up in is the dependency to fix.
    How do I fix ITMS-90338 in ReachabilitySwift?
    Update the library to a release that no longer references the flagged symbol, or replace it. For network reachability, Apple's Network framework and NWPathMonitor cover the same need without a third-party dependency, which removes the problem at the source. After updating or replacing the library, rebuild and resubmit, since the symbol reference lives in the compiled binary.
    Could ITMS-90338 be a false positive?
    Yes. The check matches symbol names, so a public method or property whose name coincides with a private Apple selector can be flagged even though it never calls a private API. In a genuine collision you can reply to App Review explaining that the symbol is your own. A reply is slower and less certain than removing the cause, so prefer updating or replacing the dependency when you can.
    Does fixing ITMS-90338 require a new build?
    Yes. The non-public symbol reference is compiled into the binary, so updating the SDK, replacing it, or renaming a colliding method all change the build. You upload a new build and it re-enters processing and review. A metadata reply cannot clear ITMS-90338 unless you are arguing a false positive, and even then a clean build is the more reliable resolution.

    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