Skip to content

[BUG] iOS Simulator panel helper (claude-ios-sim) crashes on launch on macOS 27 beta — seatbelt profile blocks Metal's new per-bundle shader-cache directory #80472

Description

@gwe-mg

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

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 getShaderCacheMainFoldercopyCacheMainFolder("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:

  1. 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.
  2. 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

  1. 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.
  2. 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.
  3. 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

  1. macOS 27 beta 4 (26A5388g) on Apple Silicon, Claude Desktop 1.24012.1.
  2. 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"
  3. Boot any iOS simulator (e.g. xcrun simctl boot <udid>).
  4. In Claude Desktop, open the iOS Simulator panel / let Claude Code attach to the simulator and grant device access.
  5. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingduplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions