[BUG] iOS Simulator: device discovery broken on Xcode 27 — SimulatorKit.framework moved to Contents/SharedFrameworks; real error swallowed as "No booted simulator found"
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Relationship to existing issues (please read first): this same root cause was reported in #79991, which was closed as not planned on 2026-07-22 with no comment. I'm re-raising it because (a) that report concluded there is no working configuration, whereas there is a verified workaround (below) that fully restores the panel's control plane, and (b) the second half of this report — the misleading error message — is not covered there and is cheap to fix. It is not #80041 (that one is about /var/db/xcode_select_link being absent; here it exists and is correct). If the closure was deliberate, a one-line rationale on either issue would help — right now the failure is silent and self-inflicted-looking to every user hitting it.
With Xcode 27 beta selected, every iOS Simulator attach / launch fails with:
No booted simulator found. Boot one with: xcrun simctl boot <device>
…even though a simulator is booted, available, and fully usable from the shell (xcrun simctl list devices booted shows it Booted, isAvailable: true, availabilityError: null, and simctl screenshot/launch/tap against that same UDID all work).
The real failure is only visible in ~/Library/Logs/Claude/main.log: FBControlCore cannot load SimulatorKit.framework, because it looks for it at the pre-Xcode-27 location <Xcode>/Contents/Developer/Library/PrivateFrameworks/SimulatorKit.framework. In Xcode 27 that framework moved to <Xcode>/Contents/SharedFrameworks/SimulatorKit.framework, and the old directory does not exist at all.
Two facets, one root cause:
- The path. SimulatorKit is resolved from a location Xcode 27 no longer uses, so device discovery fails outright on Xcode 27. Since Xcode 27 also replaced Simulator.app with the Device Hub, anyone moving to it loses the panel entirely.
- The reporting.
listDevicesfailures are caught and collapsed into the generic "No booted simulator found" message. That message actively misdirects: it tells you to boot a device that is already booted, so the debugging effort goes into CoreSimulator state, re-booting devices, restarting the app, and reinstalling Xcode — none of which can ever help. The actual loader error never reaches the user.
What Should Happen?
- Device discovery should work with Xcode 27 selected. Resolve
SimulatorKit.frameworkfrom<Xcode>/Contents/SharedFrameworks/, keeping the legacy<Xcode>/Contents/Developer/Library/PrivateFrameworks/path as a fallback for Xcode 26 and earlier. (Same treatment likely applies to any other framework the helper loads by absolute path out of the Xcode bundle — worth auditing them together rather than one at a time as each Xcode moves.)
- When
listDevicesfails, surface the underlying error. "No booted simulator found" should be reserved for the case where enumeration actually succeeded and returned no booted devices. If enumeration itself threw, the message should say so and include the loader error — e.g. "Could not enumerate simulators: SimulatorKit.framework failed to load from <path>". That one line would have turned a multi-hour investigation into a one-minute fix.
Error Messages/Logs
What the user sees (tool / panel):
No booted simulator found. Boot one with: xcrun simctl boot <device> — then retry this action.
What is actually happening — ~/Library/Logs/Claude/main.log:
[warn] [Simulator] listDevices failed: Error: [Simulator] listDevices: Simulator framework failed to load:
Error Domain=com.facebook.FBControlCore Code=0
"Attempting to load a file at path
'/Applications/Xcode-beta.app/Contents/Developer/Library/PrivateFrameworks/SimulatorKit.framework',
but it does not exist"
Proof the device is genuinely booted and healthy at the same moment:
$ xcrun simctl list -j devices booted
com.apple.CoreSimulator.SimRuntime.iOS-18-3
{"name": "iPhone 16 Pro", "state": "Booted", "isAvailable": true, "availabilityError": null}
Proof the Xcode selection is correct (i.e. not #80041):
$ xcode-select -p
/Applications/Xcode-beta.app/Contents/Developer
$ ls -l /var/db/xcode_select_link
lrwxr-xr-x root wheel /var/db/xcode_select_link -> /Applications/Xcode-beta.app/Contents/Developer
Proof of where the framework actually lives in Xcode 27:
$ find /Applications/Xcode-beta.app -maxdepth 5 -name SimulatorKit.framework
/Applications/Xcode-beta.app/Contents/SharedFrameworks/SimulatorKit.framework
$ ls /Applications/Xcode-beta.app/Contents/Developer/Library/PrivateFrameworks
ls: ...: No such file or directory # the whole legacy directory is gone
Steps to Reproduce
Requires Xcode 27 (beta) as the selected Xcode. No project or code is needed — this reproduces against any booted simulator.
- Install Xcode 27 beta. Make it the selected toolchain and ensure no Xcode 26.x remains selected:
``bash``
sudo xcode-select -s /Applications/Xcode-beta.app
xcode-select -p # => /Applications/Xcode-beta.app/Contents/Developer
- Boot any simulator and confirm the OS agrees it is booted:
``bash``
xcrun simctl boot "iPhone 16 Pro"
xcrun simctl list devices booted # => iPhone 16 Pro (<UDID>) (Booted)
- Confirm the device is genuinely usable outside Claude (this is what makes the error message wrong, not merely unhelpful):
``bash``
xcrun simctl io <UDID> screenshot /tmp/shot.png # succeeds
- In Claude Desktop, attach the iOS Simulator panel (or call the
controltool with{"action":"attach"}). - Observed:
No booted simulator found. Boot one with: xcrun simctl boot <device>. Same for{"action":"launch"}. Restarting the helper, restarting Claude Desktop, and re-booting the simulator all make no difference. - Read the real error:
``bash`
grep "listDevices failed" ~/Library/Logs/Claude/main.log | tail -1
Simulator framework failed to load: ... '<Xcode>/Contents/Developer/Library/PrivateFrameworks/SimulatorKit.framework', but it does not exist`
=>
Verified workaround (restores device discovery, attach, launch, and input injection immediately — no restart of Claude Desktop required):
mkdir -p /Applications/Xcode-beta.app/Contents/Developer/Library/PrivateFrameworks
ln -s ../../../SharedFrameworks/SimulatorKit.framework \
/Applications/Xcode-beta.app/Contents/Developer/Library/PrivateFrameworks/SimulatorKit.framework
(A relative symlink so it survives the bundle being moved; it does not survive reinstalling Xcode.)
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.193
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Environment
- Claude Desktop 1.24012.1 (the bug is in the bundled helper
Contents/Helpers/Claude iOS Sim.app, not the CLI) - Claude Code CLI 2.1.193
- macOS 27.0 beta (26A5388g), Apple M3 Pro
- Xcode 27.0 beta, the only Xcode installed; CoreSimulator framework 1166
- Simulator: iPhone 16 Pro, iOS 18.3.1 runtime (22D8075)
After the workaround, a second and separate failure remains — I'm noting it here rather than filing a duplicate, because it looks like the same underlying failure already reported in #80142 (video plane never comes up; panel unusable):
With device discovery fixed, attach succeeds and logs the resolution, then the sidecar aborts ~6 s later while bringing up video, and the panel never renders a frame:
[info] [Simulator] attached ios iPhone 16 Pro (iOS 18.3) (…) 1206x2622
[warn] [Simulator] sidecar exited code=134 sig=null
[warn] [Simulator] sidecar crash — detaching 1 iOS device(s)
#80142 reports this as a startVideo timeout with no crash cause. On this machine it is a hard SIGABRT with a symbolicated backtrace, which may be the missing cause for that issue — an uncaught NSInvalidArgumentException (nil into an NSArray) inside macOS 27's Metal shader-archive telemetry, on CoreImage's first Metal-context init:
CoreFoundation -[__NSPlaceholderArray initWithObjects:count:]
CoreFoundation +[NSArray arrayWithObjects:count:]
Metal __39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke (dispatch_once)
Metal -[_MTLDevice recordBinaryArchiveUsage:]
Metal -[_MTLBinaryArchive loadFromURL:error:]
Metal -[_MTLBinaryArchive initWithOptions:device:url:error:]
CoreImage +[CIKernelLibrary(Internal) internalBinaryArchiveWithName:device:]
CoreImage CI::PrecompiledUberFunctions::PrecompiledUberFunctions(CI::MetalContext const*)
CoreImage CI::MetalContext::init(id<MTLCommandQueue>, char const*)
I could not reproduce it outside the shipped helper. A standalone Swift program exercising the identical path (Metal-device CIContext + a gaussian blur, forcing CI::MetalContext::init → internalBinaryArchiveWithName:) renders successfully in every replicated condition: plain; under the shipped claude-ios-sim.sb sandbox profile via sandbox-exec with all six params; with hardened runtime + library validation; hardened and sandboxed; under the Contents/Helpers/disclaimer wrapper; with env -i / no HOME / no TMPDIR; on every MTLCopyAllDevices() device; and after clearing or redirecting the com.apple.metal, com.apple.metalfe and SimMetalHost caches. The helper still crashes identically under both Xcode 26.6 and Xcode 27 selections. No sandbox denials appear in the unified log.
Two things would have made that diagnosable in the field, and may help whoever picks up #80142:
- The sidecar's stderr is not captured into
main.log— theNSInvalidArgumentExceptionreason (which names the nil element) goes nowhere. Capturing sidecar stderr would have handed you the cause directly. - Hardened runtime without
get-task-allowblocks attaching a debugger, so the crash cannot be investigated locally beyond the.ipsfiles.
Happy to attach on request: the 5 identical claude-ios-sim-*.ips crash reports, the ~15-line Swift repro, and the full main.log excerpts.