Back to blog
FILE 0xDB·ITMS-90111 WASN'T MY XCODE — IT WAS MY BETA MACOS BUILD MACH

ITMS-90111 wasn't my Xcode — it was my beta macOS build machine

July 14, 2026 · ios, codesign, debugging, ci

App Store review bounced an iOS build with ITMS-90111: Unsupported SDK or Xcode version — App submissions must use the latest Xcode and SDK Release Candidates.

That message is a lie. I was on the latest submittable Xcode. Chasing what it actually meant cost me two rejected builds and one very convincing wrong theory. Here's the whole trail, including the dead end, because the dead end is where most people (me included) stop.

The red herring: "your Xcode is too old"

The Mac was running Xcode 26.6 (17F113) with the iOS 26.5 SDK. That's the newest shipping Xcode. The next one up — Xcode 27 — is still in beta, and you can't submit App Store builds with a beta toolchain. So there was literally nothing newer to install. The rejected build had already used the latest submittable everything.

When the error text and the evidence disagree this hard, stop trusting the error text and go look at the actual binary.

Reading the archive

I unpacked the .ipa and checked the platform stamps on every Mach-O:

$ vtool -show-build Payload/App.app/App
  platform IOS
    minos 16.0
      sdk 26.5
$ vtool -show-build Payload/App.app/Frameworks/libswiftCompatibilitySpan.dylib
  platform IOS
      sdk 26.4

All platform IOS, all released SDKs. Nothing beta, nothing exotic. The binary's platform stamps were fine. So the "unsupported SDK" text was pointing at something the SDK version couldn't explain.

The detour that looked like the answer

I was building headlessly — xcodebuild archive driven over SSH from another machine — and the archive was dying in the CopySwiftLibs phase:

/usr/bin/codesign --force --sign <IDENTITY> .../Frameworks/libswiftCompatibilitySpan.dylib
libswiftCompatibilitySpan.dylib: replacing existing signature
libswiftCompatibilitySpan.dylib: errSecInternalComponent

errSecInternalComponent from codesign is a real, nasty bug and it is worth knowing: the signing identity's private key lives in the login keychain, and reaching it requires being inside the GUI (Aqua) security session. An SSH session isn't. Unlocking the keychain and setting the partition list — the internet's stock advice — does not fix it:

# necessary for CI in general, but did NOT clear errSecInternalComponent:
security unlock-keychain -p "$PW" ~/Library/Keychains/login.keychain-db
security set-key-partition-list -S apple-tool:,apple:,codesign: \
    -s -k "$PW" ~/Library/Keychains/login.keychain-db

What fixes it is running the whole build inside the logged-in GUI session:

sudo launchctl asuser 501 sudo -u youruser -i /path/to/build.sh

(501 is the console user's UID.) With that wrapper, codesign reached the key, the embedded Swift dylib signed cleanly, exportArchive produced a valid .ipa, and altool uploaded with no errors.

So I fixed the signing, uploaded a clean build, resubmitted — and felt clever.

Then Build 2 got the exact same rejection

ITMS-90111 again. A build that was signed correctly, uploaded with zero errors, and showed a valid signature in App Store Connect. That killed the signing theory dead: a malformed signature was never the cause, because the correctly signed build was rejected identically. When your fix "works" and the symptom is byte-for-byte unchanged, your fix wasn't the fix.

Back to first principles: what is stamped on the binary that I hadn't checked? Not the SDK — the build machine.

$ plutil -extract BuildMachineOSBuild raw App.app/Info.plist
26A5368g
$ sw_vers
ProductVersion:  27.0
BuildVersion:    26A5368g

26A5368g is a beta macOS. Apple's ingestion pipeline reads BuildMachineOSBuild and rejects binaries produced on an unreleased OS — and it reports that rejection as ITMS-90111, the same code it uses for a too-old Xcode. Same lossy code, completely different cause. The Apple Developer Forums have a long thread (763451) of people hitting exactly this after opting their daily driver into a macOS beta.

Nothing about my sources, my Xcode, my SDK, or my signing was ever wrong. The machine I built on was running an OS Apple won't accept builds from.

What actually fixes it

Build on a released macOS. Options, worst to best for a machine you use daily:

The CI path wins: it fixes the real bug (build-machine OS) and the detour bug (headless signing) in one move, and it means "works when I click Archive on my beta laptop" stops being load-bearing.

The takeaways