Skip to content

Uncaught FBSimulatorControl exception kills RocketSim app during interact tap churn #1089

Description

@vdhamer

This is the README from the zip file that contains a shell script that drives RocketSim to reproduce the problem.
The README and repro.sh files are by Claude Code and are enough to reproduce the problem.

The included sample-crash.ips has the same crash pattern as various recent .ips files with my own app.
The standard iOS Settings app running on an arbitrary simulator is apparently enough to demo the problem.
The repro.sh indeed behaves here as claimed. Here it runs on an M3 laptop with 24 GB of RAM.
We (Claude and I) believe that this is a race condition like problem, so it may show up in some environments only.

Peter (the README text repeated below and the script is by Claude Code / Fable).

=================

RocketSim 16.2 crash repro: uncaught FBSimulatorControl exception kills the app during interact tap churn

Minimal, standalone reproduction of an intermittent RocketSim crash, for AvdLee/RocketSimApp.
No custom app needed — it drives the stock Settings app (com.apple.Preferences) on a
stock iPhone simulator with nothing but xcrun simctl and the rocketsim CLI.

The bug

RocketSim 16.2 (build 320) intermittently aborts the entire app (SIGABRT) while a
screenshot-automation script is running. The crash is an uncaught NSException on a
background GCD queue
, so nothing can catch it and the whole app goes down:

Thread ... Crashed (queue: com.apple.root.user-initiated-qos)
  libsystem_c.dylib          abort
  libc++abi.dylib            demangling_terminate_handler()
  libobjc.A.dylib            _objc_terminate()
  ...
  Foundation                 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
  FBSimulatorControl         +[FBSimulatorLaunchCtlCommands commandsWithTarget:]
  FBControlCore              -[FBiOSTargetCommandForwarder createCommandForClass:]
  FBControlCore              -[FBiOSTargetCommandForwarder obtainCommandForClass:]
  FBControlCore              -[FBiOSTargetCommandForwarder forwardingTargetForSelector:]
  ... (NSInvocation forwarding via FBLoggingWrapper / FBSimulator) ...
  FBSimulatorControl         +[FBSimulatorAccessibilityCommands remediationRequiredForSimulator:translationObject:macPlatformElement:]
  FBSimulatorControl         __110+[FBSimulatorAccessibilityCommands accessibilityElementWithTranslationRequest:simulator:remediationPermitted:]_block_invoke
  FBControlCore              __25-[FBFuture onQueue:fmap:]_block_invoke
  libdispatch.dylib          _dispatch_root_queue_drain / _dispatch_worker_thread2

So: an interact tap whose element lookup fails goes down the remediation path
(remediationRequiredForSimulator:...), which forwards into
+[FBSimulatorLaunchCtlCommands commandsWithTarget:]; an NSAssert in there fires,
and because this happens inside an FBFuture block on a root dispatch queue, the
exception is never caught and _objc_terminate aborts RocketSim.

Trigger pattern

A screenshot pipeline that, per captured screen:

  1. simctl terminate + simctl launch the app under test (relaunch churn), then
  2. issues a few best-effort rocketsim interact tap --label <label> --timeout 1
    calls for elements that are usually not on screen (dismissing possible
    first-run alerts; element_not_found is the normal, expected result), then
  3. rocketsim screenshot.

The crash is a race between the tap machinery's target/launchctl bookkeeping and the
app relaunch churn. It is intermittent — the original pipeline (28 such cycles per run)
crashed RocketSim several times a day, and it likely fires more readily on slower or
more heavily loaded machines. 24 crash reports with this exact stack were collected on
this machine over two days (2026-07-17/18).

Aftermath

After the crash, a relaunched RocketSim answers CLI IPC within ~1 second, but takes
another 25–50 s before it re-detects the already-booted simulator (until then the CLI
reports "No simulator found with UDID ..."), so simple immediate-retry logic in calling
scripts fails too.

Environment (values captured on the reproducing machine)

RocketSim 16.2.0 (build 320)
macOS 26.5.2 (25F84)
Xcode 27.0 (27A5218g)
Simulator iPhone 17 Pro, iOS 27.0 (any stock iPhone simulator should do)
Target app com.apple.Preferences (stock Settings — preinstalled everywhere)

Crash reports land in ~/Library/Logs/DiagnosticReports/RocketSim-*.ips
(exception EXC_CRASH (SIGABRT), abort() called, faulting queue
com.apple.root.user-initiated-qos). A sample report from this machine is included as
sample-crash.ips (if attached alongside this repro).

How to run

./repro.sh                     # 50 iterations, sequential taps (default)
./repro.sh --iterations 200    # more attempts
./repro.sh --concurrent-taps   # fire the 3 taps in parallel (wider race window)
./repro.sh --udid <UDID>       # pin a specific simulator

The script:

  • picks a booted iPhone simulator (or boots the newest available iPhone),
  • makes sure RocketSim.app is running and waits until it can actually screenshot
    the simulator,
  • then loops: simctl terminate + simctl launch Settings → three
    interact tap --label RSCrashReproNoSuchElement --timeout 1 calls → one
    rocketsim screenshot,
  • watches for the crash by monitoring the RocketSim PID and new RocketSim-*.ips
    files in ~/Library/Logs/DiagnosticReports/, and reports the iteration at which
    RocketSim died.

Exit status 0 means the crash reproduced (the iteration number and the fresh .ips
path are printed); exit status 1 means it survived all iterations — being a race,
it doesn't fire every run, so re-run or use --iterations 200 / --concurrent-taps.

What to expect

Each iteration takes roughly 5–10 s. On a successful repro you'll see something like:

-- iteration 2/50
  screenshot failed — checking whether RocketSim died...

*** RocketSim CRASHED during iteration 2/50 ***
Crash report: /Users/you/Library/Logs/DiagnosticReports/RocketSim-2026-07-18-....ips
Expected signature: NSAssertionHandler failure in
  +[FBSimulatorLaunchCtlCommands commandsWithTarget:]
  on queue com.apple.root.user-initiated-qos (uncaught NSException -> SIGABRT).

Open the .ips and check the faulting thread for the
+[FBSimulatorLaunchCtlCommands commandsWithTarget:] assertion under
FBSimulatorAccessibilityCommands — that's this bug.

Observed repro rate

On this machine (M-series MacBook, otherwise idle): 3 runs out of 3 crashed, at
iterations 2, 1 and 2
— i.e. within ~15 seconds of the loop starting, with the default
sequential taps (--concurrent-taps was never needed). Every crash produced an .ips
with the exact stack above. Tapping immediately after simctl launch (as this script
does) appears to hit the race far more reliably than the original screenshot pipeline,
which waited for the app to settle before tapping and "only" crashed a few times per day.

Suggested fix directions

  • Guard/@try the remediation path so an assertion in
    +[FBSimulatorLaunchCtlCommands commandsWithTarget:] fails the single tap request
    (e.g. as element_not_found or an explicit error) instead of leaving an NSException
    uncaught on a root GCD queue.
  • Separately: after a RocketSim restart, the 25–50 s re-detection delay for an
    already-booted simulator makes crash recovery in client scripts painful; a faster
    initial device scan would soften the blast radius of any such crash.

RocketSimCrashRepro.zip

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions