On 20 September my weekly app release job ran from start to finish and submitted nothing. The code compiled. Version 1.5.4 build 39 was already live on the App Store. What the job could not find was anywhere to run the tests, and my release script will not submit a build whose tests have not gone green.
Xcode 27.0 had installed on the machine three days earlier, on 17 September. Build 27A266a, by xcodebuild -version. Updating Xcode replaces the app in /Applications. It does not replace the privileged components that app depends on, which sit under /Library/Developer/PrivateFrameworks and are owned by root:wheel. CoreSimulator was still at 1051.55 where Xcode 27 wants 1171.7.0. CoreDevice was at 518.33.
xcodebuild said so plainly enough. "Current version (1051.55.0) is older than build version (1171.7.0)", it reported, and then that simulator device support was disabled. After that it could not find a device to test on. The macOS fallback in my script failed too, because with CoreDevice stale the DVTCoreDeviceCore plugin that resolves real devices would not load.
The hang
My first instinct was to look at the simulators themselves, so I ran xcrun simctl list devices. It never came back.
simctl in Xcode's bin directory is not a binary. It is a 32-line bash wrapper. Line 9 pins EXPECTED_VERSION to 1171.7. Line 10 reads the installed CoreSimulator version out of that root-owned Info.plist. If the installed version is missing or older, line 30 runs xcodebuild -runFirstLaunch before handing off to the real simctl underneath.
-runFirstLaunch installs system components into root-owned directories, and the process list showed what that costs: SecurityAgent, the macOS password panel, running as a child of the runFirstLaunch process. Nothing about that panel reaches a scheduled run's stdout. The job sits there. I killed it, called the real simctl directly, and every simulator and runtime was present. Nothing had been deleted. The wrapper was trying to repair the machine and waiting for a human to let it.
The check that needs no password
man xcodebuild documents the thing I should have been calling all along. Of -checkFirstLaunchStatus it says: "Exits with a non-zero code if additional system content needs to be installed, using -runFirstLaunch. Exits with 0 if system components are up-to-date." The published mirror of the Xcode man pages at keith.github.io/xcode-man-pages carries the same wording.
It takes no password and returns immediately. On this machine it now exits 0. Called before the test step, it turns a job that hangs into a job that stops on its first line with a message a person can act on. The password itself is unavoidable. I ran sudo xcodebuild -runFirstLaunch on 21 September, CoreSimulator went to 1171.7 and CoreDevice to 642.16, and for about two minutes afterwards xcodebuild still saw no devices at all while CoreSimulator rebuilt its device set.
The second trap
Two release attempts failed after that fix, and the cause was sitting on line 44 of my release script. SIM_DESTINATION="platform=iOS Simulator,name=iPhone 17 Pro". It names a device and no OS version. The man page says the OS key takes "the string latest (the default) to indicate the most recent version of iOS supported by this version of Xcode", and the mirror agrees. Latest had just become 27.0.
The iOS 27.0 runtime ships no iPhone 17 Pro. Its device set is iPhone 18 Pro, 18 Pro Max, 17, 17e and Air. The 17 Pro and 17 Pro Max existed on 26.5 and did not carry forward. That line went into the script on 6 September and resolved cleanly through the 1.5.4 release on 15 September. It resolved to nothing on 21 September, because the phone it named had aged out of the newest runtime.
The error text sends you the wrong way. It prints the specifier it failed on, { platform:iOS Simulator, OS:latest, name:iPhone 17 Pro }, and then a line about My Mac's macOS platform not matching, which starts you investigating a Mac destination that was never in play. Read the specifier. When a failure prints OS:latest, look for the device on the newest runtime before assuming it has left the machine.
One command fixes it. xcrun simctl create "iPhone 17 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro com.apple.CoreSimulator.SimRuntime.iOS-27-0. The device type and the runtime both still exist and nobody had paired them. 238 tests ran, none failed, and 1.5.5 build 40 went to review in the same session.
A major Xcode release changes which components count as current and which runtime counts as latest, and a script that names neither finds out by failing somewhere deep. Two lines cover it. -checkFirstLaunchStatus before the test step, so a stale machine stops on a message instead of a password prompt. An explicit OS on the destination, so a device that ages out of the newest runtime fails by name. Both go into the release script before Xcode 28.