iOS Simulator sidecar aborts on every frame render (SIGABRT in -[_MTLDevice recordBinaryArchiveUsage:])

Status Closed — not planned
Maintainer reply None cached
Activity 2 comments · opened Aug 29, 2026 · closed Aug 29, 2026

Bug report — Claude Code iOS Simulator: sidecar aborts on every frame render

Claude 1.40609.0 · macOS 27.0 (26A5378j) · Xcode 27.0 (27A5252f) · Hardware M5 Max (J716c)

Summary

The claude-ios-sim helper crashes with SIGABRT on every frame render. attach and all
input actions work — tap lands and changes app state on both an iPhone 17 Pro and an Apple
Watch Ultra 3 — but screenshot and the panel's live video stream kill the sidecar within ~1s.
The panel therefore opens and immediately dies (failed to open frame stream), and every
subsequent tool call returns the "restarting after a crash" backoff.

Deterministic: 14 crash reports in a 5-minute window, zero successful frame renders ever on
this machine.

Crash

~/Library/Logs/DiagnosticReports/Retired/claude-ios-sim-2026-08-29-*.ips

NSInvalidArgumentException: -[__NSPlaceholderArray initWithObjects:count:]:
  attempt to insert nil object from objects[0]
__39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke
_dispatch_once_callout
-[_MTLDevice recordBinaryArchiveUsage:]
-[_MTLBinaryArchive loadFromURL:error:]
-[_MTLBinaryArchive initWithOptions:device:url:error:]
+[CIKernelLibrary(Internal) internalBinaryArchiveWithName:device:]
CI::PrecompiledUberFunctions::PrecompiledUberFunctions(CI::MetalContext const*)
CI::new_uber_functions(CI::MetalContext const*)
CI::MetalContext::init(id<MTLCommandQueue>, char const*)
+[CIContext(Internal) internalContextWithMTLCommandQueue:options:]
+[CIContext contextWithMTLDevice:options:]
FBSurfaceImageGenerator.image()
FBSimulatorImage.image()

What objects[0] is

Disassembly of __39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke:

+48  ldr  x0, [x8, #0x230]
+56  bl   <objc_msgSend stub>          ; [NSBundle mainBundle]
+60  bl   <objc_msgSend stub>          ; -bundleIdentifier
+64  cbz  x0, <+268>                   ; GATE: nil bundle id -> early exit
+72  ldr  x8, [x8, #0x150]
+76  cmn  x8, #0x1
+80  b.ne <+316>                       ; GATE: only on the uninitialised sentinel
+88  ldr  x8, [x8, #0x128]             ; objects[0] = shader cache path   <-- NIL
+104 add  x9, x9, #0x7a8               ; objects[1] = @"archiveUsage.db"
+108 stp  x8, x9, [sp, #0x18]
+124 mov  w3, #0x2                     ; count = 2
+128 bl   +[NSArray arrayWithObjects:count:]   ; throws

getShaderCachePath.cold.1 is the immediately adjacent symbol in Metal's __text, naming the
producer of objects[0]. Metal is building @[getShaderCachePath(), @"archiveUsage.db"] and
the shader-cache path is nil.

Likely cause — claude-ios-sim.sb denies the Metal shader cache

Metal's shader cache lives in $DARWIN_USER_CACHE_DIR/com.apple.metal — the C/ directory.
The profile allows writes only under CORESIM_HOME, CORESIM_LOGS, DARWIN_TMP (the T/
dir) and /private/var/tmp. Probed directly under the shipped profile:

$ sandbox-exec -f claude-ios-sim.sb <real params> touch $DARWIN_USER_CACHE_DIR/com.apple.metal/.probe
touch: .../C/com.apple.metal/.probe: Operation not permitted     # exit 1

$ sandbox-exec -f claude-ios-sim.sb <real params> touch $DARWIN_USER_TEMP_DIR/.probe
                                                                  # exit 0

Candidate one-line fix:

(allow file-write* (subpath (param "DARWIN_CACHE")))   ; scoped to com.apple.metal

Confidence: strongly supported, not formally closed. No local repro reaches the crash
state, because the +64 gate requires a non-nil mainBundle.bundleIdentifier and the
+80 gate requires a still-uninitialised sentinel (first call only). The last link — that the
write-deny is what makes getShaderCachePath() return nil — is inference from the probe, not
a reproduction.

Ruled out (tested, not assumed)

  • Missing version keys in the helper's Info.plist. It genuinely has no CFBundleVersion

or CFBundleShortVersionString (the crash report shows Version: ???), but a repro bundle
with and without those keys behaves identically. Worth fixing for hygiene; not this bug.

  • user-preference-read denials as the sole cause. sandboxd logs three real ones

(kcfpreferencesanyapplication, com.apple.accessibility, com.apple.universalaccess), and
adding (allow user-preference-read) does not change the CIContext path on its own.

Suggested fixes, in priority order

  1. Stop routing frames through CoreImage. FBSurfaceImageGenerator uses a CIContext

only to turn an IOSurface into a CGImage. CGImageCreate over the locked surface, or
vImage, removes the whole Metal / CoreImage / binary-archive dependency and is faster.

  1. Catch it. This is an ObjC NSInvalidArgumentException and is catchable. Today one

Apple-side throw takes down the sidecar and detaches every device attached to it.

  1. Add a simctl io <udid> screenshot still-frame fallback. The helper already shells out

to simctl for boot / shutdown / probing, so the plumbing exists.

  1. Allow the Metal shader cache in the seatbelt profile (above).

Unrelated second defect — the setup wizard's Xcode check

On a Mac with only Xcode-beta.app and no /var/db/xcode_select_link, the wizard is stuck on
"Select Xcode" and tells the user to fix it in Xcode → Settings → Locations, where everything
already looks correct. xcode-select -p and Xcode's own picker both resolve correctly through
xcselect's single-Xcode fallback; only the link file is missing.

  • The check reads realpath('/var/db/xcode_select_link') alone, so it cannot see a working

fallback configuration.

  • Its suggested fix path is hardcoded to /Applications/Xcode.app. On a beta-only machine

that path does not exist, so xcodeSelectFixPath falls to "" and the UI renders the
"open Settings → Locations" copy — advice that cannot resolve the problem.

  • The sidecar's XCODE_APP sandbox param resolves as

realpath(link) ?? $DEVELOPER_DIR, also falling back to the literal /Applications/Xcode.app,
so process-exec would be scoped to a non-existent bundle.

Fix: derive both the check and the suggested command from xcode-select -p, and use the real
developer dir for XCODE_APP.

Workaround for users: sudo xcode-select -s /Applications/Xcode-beta.app/Contents/Developer.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗