iOS Simulator panel crash-loops on macOS 27 beta: seatbelt profile denies Metal's new cache-dir writes
Environment
- Claude desktop app 1.34493.1 (macOS), iOS Simulator panel (
claude-ios-simhelper) - macOS 27.0 beta (26A5416b), Apple Silicon
- Xcode 26.6 release selected (
xcode-select), iOS 26.0 simulator runtime booted
Summary
On macOS 27 beta 26A5416b, the Claude Code iOS Simulator panel crashes within seconds of every attach — the sidecar exits, the supervisor relaunches it, and after a few cycles it gives up ("stopped retrying after repeated crashes"). The crash is an uncaught NSInvalidArgumentException inside Metal while CoreImage initializes, and the root cause is an interaction between the helper's seatbelt profile (Claude.app/Contents/Resources/claude-ios-sim.sb) and new Metal behavior in this macOS beta.
Crash signature
Every .ips for claude-ios-sim shows the same last-exception backtrace:
*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]
CoreFoundation -[__NSPlaceholderArray initWithObjects:count:]
CoreFoundation +[NSArray arrayWithObjects:count:]
Metal __39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke
libdispatch _dispatch_once_callout
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*)
It fires the moment the frame stream opens (first CoreImage/Metal context in the helper).
Root cause
On 26A5416b, Metal's recordBinaryArchiveUsage: writes usage data under DARWIN_USER_CACHE_DIR (/var/folders/.../C/) when CoreImage loads its precompiled kernel archive. The seatbelt profile only allows writes to the CoreSimulator dirs, DARWIN_TMP, and /private/var/tmp — the user cache dir is denied. The denied handle surfaces as a nil in an NSArray literal inside the dispatch_once block, and the helper aborts.
Verified by bisection with a minimal repro:
// ci_repro.swift — crashes under the profile, renders fine without it
import CoreImage
import Metal
let dev = MTLCreateSystemDefaultDevice()!
let ctx = CIContext(mtlDevice: dev)
let img = CIImage(color: .red).cropped(to: CGRect(x: 0, y: 0, width: 8, height: 8))
_ = ctx.createCGImage(img, from: img.extent)
print("CI+Metal render OK")
- Run plain: renders OK.
- Run via
sandbox-exec -f claude-ios-sim.sb(same-Dparams the app passes, binary placed insideHELPER_BUNDLEsoprocess-execallows it): crashes with the exact signature above. - Same sandboxed run with one appended rule —
(allow file-write* (subpath "<DARWIN_USER_CACHE_DIR>"))— renders OK.
Narrower candidates were tested and do not fix it (so it's the cache-dir write, not a read): allowing full $HOME file-read-data doesn't help; CI_USE_SOFTWARE_RENDERER=1 doesn't help (the helper creates its CIContext with an explicit Metal device).
Suggested fix
Add the user cache directory to the profile's write allow-list, e.g.:
;; macOS 27 beta: Metal records binary-archive usage under the user cache dir
(allow file-write* (subpath (param "DARWIN_CACHE")))
with DARWIN_CACHE resolved from confstr(_CS_DARWIN_USER_CACHE_DIR) alongside the existing DARWIN_TMP param in the sidecar spawn code. Cache-dir scratch seems consistent with the profile's stated intent ("CoreSimulator device state and scratch only").
Notes for triage
- The failure is invisible in the app UI beyond generic "sidecar exited (code=134)" / crash-loop messages; the
.ipsfiles carry the signature. - A second, related trap found while investigating: the profile's
process-execallow-list (helper bundle,/usr/bin,/usr/libexec, Xcode,/Library/Developer) means an exec of/bin/zshetc. exits 71 with no crash log at all — worth a clearer supervisor message distinguishing "exec denied" from a real crash. - Local workaround applied on this machine: the one-line profile addition above (byte-exact original preserved). Happy to test a fixed build.
3 Comments
Follow-up — the crash is first-run-per-cache-lifetime, which will make it look intermittent in reports.
New differential findings (same machine, 26A5416b):
$DARWIN_USER_CACHE_DIR/com.anthropic.claude.ios-sim/com.apple.metal{,fe}.recordBinaryArchiveUsage:only needs reads, which the profile already allows.$DARWIN_USER_CACHE_DIR/com.anthropic.claude.ios-simand respawning under the pristine profile brings the crash back immediately (SIGABRT, exit 134, same stack).So the nil comes specifically from the create path of Metal's per-app usage cache. Implications for triage:
/var/folderscaches (periodic maintenance, storage pressure, some updates) — then it returns with no apparent trigger. Expect confusing "it fixed itself / it broke again" reports.CI_USE_SOFTWARE_RENDERER,$HOMEread allowances, and the top-level$DARWIN_USER_CACHE_DIR/com.apple.metaldir (repro unaffected by hiding it).The suggested fix is unchanged (allow
file-write*under the user cache dir, resolved viaconfstr(_CS_DARWIN_USER_CACHE_DIR)) — but a cheaper interim mitigation may be for the sidecar spawn code tomkdir -pthe helper's per-app Metal cache dirs before applying the sandbox, which sidesteps the create path entirely without widening the profile.Confirmed the interim mitigation empirically: on a fully stock app (an auto-update overnight replaced our patched profile — signature seal intact, no local modifications), simply pre-creating the two empty directories
takes the panel from crash-loop (SIGABRT every frame-stream open) to stable 60s+ streaming. Empty dirs suffice — Metal only needed the create to succeed. So the sidecar spawn code doing this
mkdir -pbefore applying the sandbox is a complete fix on 26A5416b, no profile widening required. Also a one-line user workaround for anyone hitting this on the macOS beta today.Confirming on a different beta build and chip: macOS 27.0 (26A5353q), M3 Max (Mac15,10), iOS 27.0 runtime (24A5390f) booted.
Identical signature —
NSInvalidArgumentException: attempt to insert nil object from objects[0]out ofrecordBinaryArchiveUsage:viaCI::PrecompiledUberFunctions, on thecom.facebook.FBSimulatorControl.BitmapStreamqueue. Two dozen.ipsfiles over two days, all the same stack.The
mkdir -pmitigation works here on a stock app: everyscreenshotcall failed with "restarting after a crash" before, stable streaming immediately after.Two details consistent with your triage:
xcrun simctl io <udid> screenshotcaptured frames fine throughout the crash-loop, so CoreSimulator itself is healthy and the fault is confined to the helper.$DARWIN_USER_CACHE_DIR/com.apple.metalchanged nothing, matching your finding that it is not a factor.Also worth noting for anyone landing here from a wedged-simulator symptom: none of the usual CoreSimulator resets help, since the helper is the thing crashing.