[Bug] iOS Simulator helper (claude-ios-sim) crash-loops on macOS 27 beta — uncaught NSException in Metal recordBinaryArchiveUsage via CoreImage
Environment
- Claude desktop app: 1.24012.9 (macOS)
- Helper:
/Applications/Claude.app/Contents/Helpers/Claude iOS Sim.app/Contents/MacOS/claude-ios-sim(bundle idcom.anthropic.claude.ios-sim; no CFBundleShortVersionString set) - macOS: 27.0 beta, build 26A5388g
- Xcode: 26.6 (17F113), default toolchain at
/Applications/Xcode.app/Contents/Developer - Hardware: Apple Silicon (arm64) MacBook Pro
- Simulators: iOS 27.0 runtime, default device set; multiple devices booted and healthy
Symptom
The Claude Code iOS Simulator integration is unusable: every interaction that spawns the helper (attach live panel, and headless screenshot/input actions) crashes it within seconds. The MCP server then reports "Claude Code iOS Simulator is restarting after a crash" and, after retries, "hit an internal error." Four crash reports were produced within minutes during normal use.
Additional data point: with devices booted in the default device set (verified via xcrun simctl list devices booted and the device directory under ~/Library/Developer/CoreSimulator/Devices/), attach with no arguments reported "No booted simulator found"; attach with an explicit udid succeeded (panel opened, then the helper crashed seconds later). Possibly a separate, minor device-discovery bug — mentioned in case it's related.
Crash analysis
All four reports have the identical faulting path: abort() via std::terminate from an uncaught Objective-C exception thrown during CoreImage Metal context setup:
lastExceptionBacktrace (top frames):
CoreFoundation __exceptionPreprocess
libobjc.A.dylib objc_exception_throw
CoreFoundation -[__NSPlaceholderArray initWithObjects:count:] ← nil element
CoreFoundation +[NSArray arrayWithObjects:count:]
Metal __39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke
libdispatch _dispatch_client_callout / _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*)
Termination: EXC_CRASH (SIGABRT), "Abort trap: 6", ASI: abort() called.
Reading of the stack: when the helper creates a CoreImage MetalContext, CoreImage loads its OS-shipped precompiled shader binary archive (internalBinaryArchiveWithName:). Inside that load, Metal's internal usage-telemetry (recordBinaryArchiveUsage, under dispatch_once) constructs an NSArray with a nil element and throws NSInvalidArgumentException, which nothing in the helper catches → std::terminate → abort.
The archive at fault is Apple's, inside the OS/CoreImage — i.e., this looks like a macOS 27 beta regression that the helper is exposed to, rather than a bug in the helper's own logic. Filing here because (a) the helper could plausibly guard/degrade instead of crash-looping (e.g., catch at the CIContext boundary, fall back to a non-CoreImage path, or surface a clear "OS beta incompatibility" error through the MCP tool result), and (b) you may want a known-issue note for macOS 27 beta users.
Ruled out during diagnosis
- User Metal shader cache: moved
$(getconf DARWIN_USER_CACHE_DIR)/com.apple.metalaside entirely — crash reproduced identically on next launch, with the deeper stack showing the archive comes from CoreImage's internal bundle, not the user cache. - CoreSimulator / Xcode setup:
xcode-selectpoints at the release Xcode 26.6; simulators are in the default device set;xcrun simctl io <udid> screenshotworks perfectly. Everything Apple-side except the beta's Metal telemetry path is healthy. - Stale simulators: devices freshly booted; crash occurs regardless of which booted device is targeted.
Repro steps
- macOS 27.0 beta 26A5388g, Claude desktop 1.24012.9, any iOS 27 simulator booted.
- From a Claude Code session, call the iOS Simulator MCP tool:
control { action: "attach", udid: "<booted-udid>" }(or anyscreenshotaction). - Panel opens (attach case), helper aborts within seconds; subsequent calls return "restarting after a crash" then "internal error." Crash report appears in
~/Library/Logs/DiagnosticReports/.
Reproduced 4/4 attempts across ~10 minutes.
Attachments
claude-ios-sim-2026-07-31-180417.ipsclaude-ios-sim-2026-07-31-180446.ipsclaude-ios-sim-2026-07-31-180919.ips- (plus newer
claude-ios-sim-*.ipsfrom retry attempts)
All in ~/Library/Logs/DiagnosticReports/. Note: I will attach the .ips files in a follow-up comment (attachments require the web UI).
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
IPS Files.zip
Confirming the same crash loop on another machine, with one additional data point that narrows the cause to the helper's sandbox.
Environment
claude-ios-simcrash reports in~/Library/Logs/DiagnosticReports/Retired/, oldest 2026-07-25 — so this predates recent app updatesSame signature —
SIGABRT, uncaught NSException (nil object in collection):Additional data point — unsandboxed CoreImage+Metal works fine on the same host. This minimal repro succeeds outside the helper:
So the Metal binary-archive load only fails inside the helper's seatbelt profile (
Claude.app/Contents/Resources/claude-ios-sim.sb), which has no allowances for Metal shader-cache paths — consistent with the analysis in #80472. Likely the sandbox denial turns a path/archive lookup nil, and Metal's usage-recording puts that nil into anNSArray.Also matches observed behavior precisely:
tap,text,swipe) works reliably the whole time — onlyscreenshot/panel streaming (the CoreImage frame-conversion path) dies.attachMCP calls report success right before the crash.Possibly-duplicate reports of the same underlying bug: #80177, #80472, #82864, #81520.
Root cause confirmed and a one-rule fix verified locally (same machine as my comment above — macOS 27.0 beta 26A5388g, app 1.24012.9).
Root cause: the seatbelt profile (
Resources/claude-ios-sim.sb) allows writes only to CoreSimulator dirs,DARWIN_TMP, and/private/var/tmp. On macOS 27 beta, CoreImage's Metal context creation loads a precompiled binary shader archive, and Metal needs the process's per-bundle shader-cache directory underDARWIN_USER_CACHE_DIR, i.e./var/folders/…/C/com.anthropic.claude.ios-sim/. The profile denies creating it, the path comes back nil, and-[_MTLDevice recordBinaryArchiveUsage:]throwsattempt to insert nil object→ SIGABRT.The bundle identity is the missing trigger: a bare binary running the same CoreImage/Metal code under the same profile passes (no per-bundle cache path), while the identical binary wrapped in an
.appwithCFBundleIdentifier=com.anthropic.claude.ios-simcrashes with the exact production stack. Repro:Fix (verified): one added rule, scoped to the helper's own bundle-id cache subtree:
With this appended to the shipped profile, the repro prints OK, Metal creates
C/com.anthropic.claude.ios-sim/{com.apple.metal,com.apple.metalfe}, and the real helper stops crash-looping: MCPscreenshotreturns frames and the live panel attaches and streams. Also corroborates the sandbox analysis in #80472.A
(param …)-based variant would be cleaner than the regex ifsidecarSandbox.tspassesDARWIN_USER_CACHE_DIR(siblingC/of the currentDARWIN_TMPparam) as a new parameter.Reproduced, with two additional data points.
Environment
iOS Simulatortool, bothattachand headlessscreenshot)xcode-select— so this reproduces with the beta toolchain active as well, ruling out the selected-Xcode version as a factorIsolation
Crash-loops identically with exactly one booted simulator and no other capture processes running (we killed a coexisting
serve-simstreamer and shut down a second booted device to eliminate both variables — no change).Crash stack (from
~/Library/Logs/DiagnosticReports/claude-ios-sim-*.ips)Same signature as OP, reached via the screenshot path:
Suggested fix / workaround evidence
On this same OS build, the third-party
serve-simstreamer works against the same devices: when the hardware H.264 path is unavailable it logs "H.264 was unavailable for this stream, so it fell back to MJPEG" and degrades gracefully.claude-ios-simtakes the CoreImage/Metal path unguarded, so the beta's broken Metal binary-archive load aborts the whole helper on every frame.Wrapping the
CIContext/screenshot render in an exception guard and falling back to a software renderer (kCIContextUseSoftwareRenderer) — or any non-Metal capture path — would keep the panel functional on beta OSes instead of crash-looping.