Preflight Checklist
What's Wrong?
Summary
On macOS 27 beta, the claude-ios-sim helper aborts with an uncaught NSInvalidArgumentException every time the simulator panel starts its video stream. Root cause is an interaction between the helper's seatbelt profile (claude-ios-sim.sb) and two Metal changes new in the macOS 27 beta: the shader cache moved to a per-bundle-ID directory under DARWIN_USER_CACHE_DIR, and a new -[_MTLDevice recordBinaryArchiveUsage:] code path passes the shader-cache path into +[NSArray arrayWithObjects:count:] without a nil check. The sandbox denies creating the cache directory → MTLGetShaderCachePath() is nil → Metal throws → the helper dies. 100% reproducible; the panel never comes up.
Fully diagnosed with a minimal repro and a verified user-side workaround (below). Suggested fix: allow file-write* on the helper's Metal cache subtree in claude-ios-sim.sb.
Environment
- macOS 27.0 beta 4 (build
26A5388g), Apple Silicon (M3 Max)
- Claude Desktop 1.24012.1
- Active Xcode via
xcode-select: Xcode 26.6 (17F113) at /Applications/Xcode.app (Xcode 27 beta 4 also installed as Xcode-beta.app, not selected)
- Simulator runtimes present and healthy: iOS 18.5 / 26.5 / 27.0;
simctl works normally
- Not reproducible on release macOS 26.x (the crashing Metal code path is new in the 27 beta)
Symptom
Opening the simulator panel (attach / launch) kills the helper within seconds, every time. Crash reports accumulate under ~/Library/Logs/DiagnosticReports[/Retired]/claude-ios-sim-*.ips (10 in ~20 minutes of attempts):
bundleID: com.anthropic.claude.ios-sim
EXC_CRASH (SIGABRT), abort() called, uncaught NSException
lastExceptionBacktrace (identical in all reports):
2 CoreFoundation -[__NSPlaceholderArray initWithObjects:count:] + 640 <- throws: nil object
3 CoreFoundation +[NSArray arrayWithObjects:count:] + 40
4 Metal __39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke + 132
7 Metal -[_MTLDevice recordBinaryArchiveUsage:] + 356
8 Metal -[_MTLBinaryArchive loadFromURL:error:] + 1504
9 Metal -[_MTLBinaryArchive initWithOptions:device:url:error:] + 916
10 CoreImage +[CIKernelLibrary(Internal) internalBinaryArchiveWithName:device:] + 156
11 CoreImage CI::PrecompiledUberFunctions::PrecompiledUberFunctions(CI::MetalContext const*) + 188
13 CoreImage CI::MetalContext::init(id<MTLCommandQueue>, char const*) + 472
16 CoreImage -[CIContext initWithMTLDevice:options:] + 100
18-21 FBSimulatorControl (frame-conversion pipeline of the video stream)
Root cause
Disassembly of Metal (macOS 27 beta 4) shows the crashing block builds a two-element array {MTLGetShaderCachePath(), @"archiveUsage.db"} to open an archive-usage LMDB. MTLGetShaderCachePath() resolves via getShaderCacheMainFolder → copyCacheMainFolder("com.apple.metal", create=true) → getCacheMainFolder, which does confstr(_CS_DARWIN_USER_CACHE_DIR) + stat + mkdir — and returns NULL if the directory cannot be created. The nil path then flows unguarded into arrayWithObjects:count:.
Two things changed in the macOS 27 beta:
- The shader cache is now per bundle ID:
$(getconf DARWIN_USER_CACHE_DIR)/<bundleID>/com.apple.metal/... — so every process with a fresh bundle ID must be able to mkdir there once.
- The
recordBinaryArchiveUsage: path (triggered by CoreImage's precompiled uber-function binary archive during CIContext init) is new and has no nil guard.
Meanwhile claude-ios-sim.sb (deny-by-default) only allows file-write* on CORESIM_HOME, CORESIM_LOGS, DARWIN_TMP (the T/ folder) and /private/var/tmp. The Darwin user cache dir (C/ folder) is not writable, the helper cannot create C/com.anthropic.claude.ios-sim/, MTLGetShaderCachePath() is nil, and the first CIContext created by FBSimulatorControl's video pipeline aborts the process.
Note the profile header says rules were validated per macOS release and asks for re-validation "after an Xcode or macOS bump" — this is exactly that case.
Minimal repro (no Claude involved)
// main.m — clang -fmodules -fobjc-arc main.m -o testbin
@import Foundation; @import Metal; @import CoreImage;
int main() {
id<MTLDevice> dev = MTLCreateSystemDefaultDevice();
CIContext *ctx = [CIContext contextWithMTLDevice:dev]; // <- aborts here
NSLog(@"ok %@", ctx);
return 0;
}
Wrap it in a minimal .app bundle with a bundle ID that has no existing cache dir, then run it under the shipped profile:
/usr/bin/sandbox-exec -f /Applications/Claude.app/Contents/Resources/claude-ios-sim.sb \
-D "HELPER_BUNDLE=/path/to/Test.app" -D "XCODE_APP=/Applications/Xcode.app" \
-D "USER_HOME=$HOME" -D "CORESIM_HOME=$HOME/Library/Developer/CoreSimulator" \
-D "CORESIM_LOGS=$HOME/Library/Logs/CoreSimulator" \
-D "DARWIN_TMP=$(getconf DARWIN_USER_TEMP_DIR)" \
/path/to/Test.app/Contents/MacOS/Test
Result: libc++abi: terminating due to uncaught exception of type NSException with the identical Metal/CoreImage stack. Unsandboxed, or with the cache dir pre-created, the same binary runs fine. (Repro caveat: the crash only fires while C/<bundleID>/ doesn't exist yet — any unsandboxed run of the same bundle ID creates it and masks the bug afterwards.)
Verified user-side workaround
Pre-creating the directories from outside the sandbox is sufficient — Metal handles unwritable cache files gracefully; only the missing directory is fatal:
C_DIR=$(getconf DARWIN_USER_CACHE_DIR)
mkdir -p "$C_DIR/com.anthropic.claude.ios-sim/com.apple.metal/archiveUsage.db" \
"$C_DIR/com.anthropic.claude.ios-sim/com.apple.metalfe" \
"$C_DIR/com.anthropic.claude.ios-sim/com.apple.gpuarchiver"
After this, the panel attaches, streams video, and screenshots/taps work normally on macOS 27 beta 4. Caveat: the workaround does not survive a /var/folders cleanup.
What Should Happen?
Suggested fixes
- In
claude-ios-sim.sb: allow file-write* on (subpath "<DARWIN_USER_CACHE_DIR>/com.anthropic.claude.ios-sim") (pass the resolved cache dir as a profile parameter like the existing DARWIN_TMP). Narrow, matches the profile's own narrowest-argument philosophy, and future-proofs against Metal writing shader caches from the helper.
- Alternatively (or additionally), the launcher (
sidecarSandbox.ts?) could mkdir -p the helper's Metal cache tree before spawning — that is exactly the verified workaround above.
- Worth filing a Feedback to Apple as well:
-[_MTLDevice recordBinaryArchiveUsage:] should nil-guard MTLGetShaderCachePath() — any sandboxed process that cannot create its cache dir will crash in CIContext init on macOS 27 beta.
Error Messages/Logs
## Attachments available on request
- Full `.ips` crash reports (`claude-ios-sim-2026-07-22-*.ips`, 10x identical)
- Disassembly excerpts of `__39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke`, `__MTLGetShaderCachePath_block_invoke`, `getCacheMainFolder` (macOS 27 beta 4)
Steps to Reproduce
- macOS 27 beta 4 (26A5388g) on Apple Silicon, Claude Desktop 1.24012.1.
- Make sure the helper's Metal cache dir does NOT exist yet (fresh state, default on this OS):
ls "$(getconf DARWIN_USER_CACHE_DIR)/com.anthropic.claude.ios-sim" -> "No such file or directory"
- Boot any iOS simulator (e.g.
xcrun simctl boot <udid>).
- In Claude Desktop, open the iOS Simulator panel / let Claude Code attach to the simulator and grant device access.
- As soon as the panel starts the video stream, the helper process
claude-ios-sim aborts (SIGABRT, uncaught NSInvalidArgumentException). Crash report appears in ~/Library/Logs/DiagnosticReports/claude-ios-sim-*.ips. Reproduces on every attempt.
Claude Model
Other
Is this a regression?
No, this never worked
Last Working Version
No response
Claude Code Version
2.1.217
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Warp
Additional Information
Claude Desktop 1.24012.1
Claude Code 2.1.217 (integrated)
Agent SDK 0.3.217
Preflight Checklist
What's Wrong?
Summary
On macOS 27 beta, the
claude-ios-simhelper aborts with an uncaughtNSInvalidArgumentExceptionevery time the simulator panel starts its video stream. Root cause is an interaction between the helper's seatbelt profile (claude-ios-sim.sb) and two Metal changes new in the macOS 27 beta: the shader cache moved to a per-bundle-ID directory underDARWIN_USER_CACHE_DIR, and a new-[_MTLDevice recordBinaryArchiveUsage:]code path passes the shader-cache path into+[NSArray arrayWithObjects:count:]without a nil check. The sandbox denies creating the cache directory →MTLGetShaderCachePath()is nil → Metal throws → the helper dies. 100% reproducible; the panel never comes up.Fully diagnosed with a minimal repro and a verified user-side workaround (below). Suggested fix: allow
file-write*on the helper's Metal cache subtree inclaude-ios-sim.sb.Environment
26A5388g), Apple Silicon (M3 Max)xcode-select: Xcode 26.6 (17F113) at/Applications/Xcode.app(Xcode 27 beta 4 also installed asXcode-beta.app, not selected)simctlworks normallySymptom
Opening the simulator panel (attach / launch) kills the helper within seconds, every time. Crash reports accumulate under
~/Library/Logs/DiagnosticReports[/Retired]/claude-ios-sim-*.ips(10 in ~20 minutes of attempts):bundleID: com.anthropic.claude.ios-simEXC_CRASH (SIGABRT),abort() called, uncaught NSExceptionlastExceptionBacktrace(identical in all reports):Root cause
Disassembly of Metal (macOS 27 beta 4) shows the crashing block builds a two-element array
{MTLGetShaderCachePath(), @"archiveUsage.db"}to open an archive-usage LMDB.MTLGetShaderCachePath()resolves viagetShaderCacheMainFolder→copyCacheMainFolder("com.apple.metal", create=true)→getCacheMainFolder, which doesconfstr(_CS_DARWIN_USER_CACHE_DIR)+stat+mkdir— and returns NULL if the directory cannot be created. The nil path then flows unguarded intoarrayWithObjects:count:.Two things changed in the macOS 27 beta:
$(getconf DARWIN_USER_CACHE_DIR)/<bundleID>/com.apple.metal/...— so every process with a fresh bundle ID must be able tomkdirthere once.recordBinaryArchiveUsage:path (triggered by CoreImage's precompiled uber-function binary archive duringCIContextinit) is new and has no nil guard.Meanwhile
claude-ios-sim.sb(deny-by-default) only allowsfile-write*onCORESIM_HOME,CORESIM_LOGS,DARWIN_TMP(theT/folder) and/private/var/tmp. The Darwin user cache dir (C/folder) is not writable, the helper cannot createC/com.anthropic.claude.ios-sim/,MTLGetShaderCachePath()is nil, and the firstCIContextcreated by FBSimulatorControl's video pipeline aborts the process.Note the profile header says rules were validated per macOS release and asks for re-validation "after an Xcode or macOS bump" — this is exactly that case.
Minimal repro (no Claude involved)
Wrap it in a minimal
.appbundle with a bundle ID that has no existing cache dir, then run it under the shipped profile:Result:
libc++abi: terminating due to uncaught exception of type NSExceptionwith the identical Metal/CoreImage stack. Unsandboxed, or with the cache dir pre-created, the same binary runs fine. (Repro caveat: the crash only fires whileC/<bundleID>/doesn't exist yet — any unsandboxed run of the same bundle ID creates it and masks the bug afterwards.)Verified user-side workaround
Pre-creating the directories from outside the sandbox is sufficient — Metal handles unwritable cache files gracefully; only the missing directory is fatal:
After this, the panel attaches, streams video, and screenshots/taps work normally on macOS 27 beta 4. Caveat: the workaround does not survive a
/var/folderscleanup.What Should Happen?
Suggested fixes
claude-ios-sim.sb: allowfile-write*on(subpath "<DARWIN_USER_CACHE_DIR>/com.anthropic.claude.ios-sim")(pass the resolved cache dir as a profile parameter like the existingDARWIN_TMP). Narrow, matches the profile's own narrowest-argument philosophy, and future-proofs against Metal writing shader caches from the helper.sidecarSandbox.ts?) couldmkdir -pthe helper's Metal cache tree before spawning — that is exactly the verified workaround above.-[_MTLDevice recordBinaryArchiveUsage:]should nil-guardMTLGetShaderCachePath()— any sandboxed process that cannot create its cache dir will crash inCIContextinit on macOS 27 beta.Error Messages/Logs
Steps to Reproduce
ls "$(getconf DARWIN_USER_CACHE_DIR)/com.anthropic.claude.ios-sim" -> "No such file or directory"
xcrun simctl boot <udid>).claude-ios-simaborts (SIGABRT, uncaught NSInvalidArgumentException). Crash report appears in ~/Library/Logs/DiagnosticReports/claude-ios-sim-*.ips. Reproduces on every attempt.Claude Model
Other
Is this a regression?
No, this never worked
Last Working Version
No response
Claude Code Version
2.1.217
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Warp
Additional Information
Claude Desktop 1.24012.1
Claude Code 2.1.217 (integrated)
Agent SDK 0.3.217