---
title: "Reproduce an iOS crash with logs and video | Mobster"
description: "Turn an iOS crash report into a failing check you can rerun, with the app's log, a symbolicated stack and a video of the last screens, captured on a simulator."
canonical: "https://mobster.dev/blog/reproduce-ios-crash-logs-video"
last-updated: "2026-11-14"
---

Turn an iOS crash report into a failing check you can rerun, with the app's log, a symbolicated stack and a video of the last screens, captured on a simulator.

# Reproduce an iOS crash with logs and video

30 October 2026

A crash you can’t repeat is a crash you can’t fix. The report says where the app died, but not what the person did to get there. This guide takes a crash from a report to a failing check that reproduces it on demand, with the stack, the app’s log and a video, on a simulator.

## Read the report first

Get the crash report from where it happened:

- **A simulator on your Mac:** `~/Library/Logs/DiagnosticReports`, as an `.ips` file.
- **An iPhone cabled to your Mac:** Xcode › Window › Devices and Simulators, then the phone’s device logs.
- **A TestFlight tester or the App Store:** Xcode › Window › Organizer › Crashes, and App Store Connect.
- **A phone you can’t reach:** on the phone, Settings › Privacy & Security › Analytics & Improvements › Analytics Data, the log named after your app, then Share.

Three lines tell you most of it:

- **Exception type and signal**, such as `EXC_BAD_ACCESS (SIGSEGV)` for a bad pointer, `EXC_BREAKPOINT (SIGTRAP)` for a Swift runtime trap like a force-unwrapped `nil` or an array index out of range, `EXC_CRASH (SIGABRT)` for an uncaught exception.
- **The crashed thread’s frames.** The first frame in your own module is where to look.
- **`0x8badf00d`** in the exception codes means the watchdog killed the app for blocking the main thread too long at launch or resume. That’s a hang, not a bad pointer.

If the frames are hex addresses, the report isn’t symbolicated. Xcode does it when it finds the dSYM of that exact build. Keep every shipped build’s dSYM, or the report stays unreadable.

## Find the steps

Work backwards from three facts: what the app was showing, what the tester did, and what the log says. Ask for the app version and build, the iOS version, the device model and the last thing they tapped. The log of the seconds before the crash is the best clue you’ll get, so capture it on your own run:

```
# Simulator: stream the app's logxcrun simctl spawn booted log stream --level info --predicate 'process == "YourApp"'# Simulator: record the screenxcrun simctl io booted recordVideo crash.mov
```

On an iPhone, open Console.app, pick the phone in the sidebar and filter by your app’s name. Remember that `print` output doesn’t reach the unified log: use `Logger` or `os_log` for anything you want to read after a crash.

## Turn the steps into a check

Write the flow in plain English, with the screen you expect to see at the end. Mobster fails a check as `app_crashed` when the app dies, even if every expectation held, so the expectation can be as small as “the screen is still there”:

```
# .mobster/checks/checkout-crash.yamlversion: 1name: Applying a promo code twice doesn't crash checkoutapp:  bundle: com.example.yourapp  path: .mobster/build/Build/Products/Debug-iphonesimulator/YourApp.applaunch:  args: ["-SkipOnboarding", "YES"]  url: yourapp://cartsteps:  - Tap Apply promo code, type SAVE10 and tap Apply.  - Tap Apply promo code again, type SAVE10 and tap Apply.expect:  - visible: { id: checkout_total }
```

Run it with the screen recording on:

```
mobster test .mobster/checks/checkout-crash.yaml --video
```

A check with steps runs Smart on your Claude or OpenAI key until it passes once, then replays the recorded steps with no model call. A launch-only check, with no steps, calls no model. A check that crashes never passes, so Smart runs its steps each time.

When the app crashes, the summary names the exception and the first frame in your code. Example output, from a test app that crashes on purpose:

```
✗ failed  Crash fixture stays up after launch  on iPhone 17 Pro, iOS 26.4    Crash Fixture crashed: EXC_BREAKPOINT (SIGTRAP), in specialized CrashTrigger.crashNow() (CrashFixtureApp.swift:11).    The report's Logs and Crash pane shows the stack and the app's log around the crash.
```

## What Mobster keeps

For every run on a simulator, Mobster keeps the app’s log and, on a crash, its crash report. With `--video` it records the screen too. The suite folder `.mobster/test-results/<suite-id>/` holds it all:

| File | What it holds |
|---|---|
| `index.html` | Each failed check, with its Logs and Crash pane: the top frames with your own in full ink, then the app’s log 10 seconds either side of the crash |
| `runs/<run-id>/logs/app.log` | The app’s unified log, from before launch to the verdict, stamped in seconds since the run started |
| `runs/<run-id>/crashes/*.ips` | The crash report |
| `videos/` | The screen as an H.264 MP4, 590 pixels wide |
| `junit.xml` | `<failure type="app_crashed">` with the frames, and the log window in `<system-out>` |

How it reads each source: the log comes from `xcrun simctl spawn <udid> log stream`, the crash report from `~/Library/Logs/DiagnosticReports`, and the video from `xcrun simctl io recordVideo`. Mobster names your app’s frames with the dSYM beside the `.app` or in `.mobster/build/Build/Products`, using `atos`. A Debug build already carries its names.

Two limits. First, macOS writes a simulator’s crash report after the crash: it took 61 seconds to 4 minutes on a Mac running many simulators and builds. `mobster test` waits up to 60 seconds, once, at the end of the suite, and the check still says it crashed and on which signal when the report comes later. Second, `print` isn’t in the log. Use `Logger`.

The log and the crash report can hold secrets, so each line goes through the Mobster secret filter before it’s written: passwords, one-time codes, card numbers and API keys become `••••`. The files stay on your Mac.

What it costs, measured on an M5 Max running many other simulators and builds, with a launch-only check on an iPhone 17 Pro simulator, 6 runs each, interleaved: a median 8.6 s without capture and 7.6 s with it, a difference inside the noise. A simulator’s video was 2 to 7 MB a check.

## Crashes your testers hit

`mobster asc feedback` lists the crashes from TestFlight and downloads each crash log, so you can start from the real report:

```
mobster asc feedback --app com.example.yourapp --crashes --save feedback/
```

Then write the check from the report’s device, iOS version and last screen, and run it on a simulator, where the log, the crash report and the video are captured. When the crash only happens on hardware, run the same check on a phone to reproduce the steps:

```
mobster test .mobster/checks/checkout-crash.yaml --device "Test iPhone" --testflight com.example.yourapp
```

On an iPhone a check drives only your own build and never clears its data. Keep the phone unlocked.

## When it doesn’t reproduce

- **Match the conditions.** A crash that needs a slow network, a full disk, a denied permission or low memory won’t show on a fresh simulator. A check can set `permissions`, `locale`, `content_size` and `location` on a simulator (`conditions`), and only `appearance` and `locale` on a real iPhone.
- **Run it many times.** `mobster test --repeat 20 .mobster/checks/checkout-crash.yaml` gives a pass rate. A crash that happens 1 run in 20 is a race, and the log of the failing run is the evidence. [How to fix flaky XCUITests](https://mobster.dev/blog/fix-flaky-xcuitests) covers the usual races.
- **Turn on the sanitizers.** For memory bugs, enable Address Sanitizer or Thread Sanitizer in the scheme and run the same check against that build.

[Download Mobster for Mac](https://mobster.dev/download) to run these checks on your simulators and your own iPhones: [free](https://mobster.dev/pricing) (AI runs on a supported AI plan, an API key or a model on your Mac).

[Checks](https://docs.mobster.dev/checks) lists every field of the check file, and [Device setup](https://docs.mobster.dev/device-setup) puts the helper on your iPhone.

## Questions

- ### Where are iOS crash reports on a Mac?
  A simulator's crash reports are in ~/Library/Logs/DiagnosticReports, and a connected iPhone's are in Xcode's Devices and Simulators window. TestFlight and App Store crashes are in Xcode's Crashes organizer and App Store Connect.
- ### Why does my crash report show addresses instead of function names?
  The report is unsymbolicated. Xcode symbolicates it when it can find the dSYM for that exact build, so keep the dSYM of every build you ship.
- ### Can Mobster fix a crash?
  No. It makes the crash repeatable and, on a simulator, attaches the evidence: the log, the stack with your own frames named and a video of the screens before it.

## Sources

- [Apple: acquiring crash reports and diagnostic logs](https://developer.apple.com/documentation/xcode/acquiring-crash-reports-and-diagnostic-logs)
- [Apple: symbolicating crash reports](https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report)
- [Mobster docs: logs, crashes and video](https://docs.mobster.dev/testing)
- [Mobster docs: App Store Connect](https://docs.mobster.dev/dev/app-store-connect)

## Try it on your own iPhone

Download Mobster for Mac

## More from the blog

### [How to fix flaky XCUITests](https://mobster.dev/blog/fix-flaky-xcuitests)

19 Oct 2026

### [Test an iOS app on a real iPhone from your Mac](https://mobster.dev/blog/test-ios-app-on-real-iphone)

17 Oct 2026

### [How to test an iOS app with an AI agent](https://mobster.dev/blog/ai-e2e-tests-ios-assertions)

8 Oct 2026
