Skip to main content

iOS Crash Report and AI: Which .ips Details to Give the AI

Before giving an iOS crash report to AI, pull Exception Type, Termination Reason, the crashed thread and backtrace from the .ips. Prompt template included.

To get useful AI analysis of an iOS crash report, give the AI the right parts of the .ips file, not the whole thing. Pull out the Exception Type, Termination Reason, the crashed thread (Triggered by Thread) and the Last Exception Backtrace, and hand them over with the steps to reproduce and the relevant code. After the fix, repeat the same steps and check that crash counts drop for the new build. This article covers getting the report, reading the fields, exception types, symbols, the prompt, verifying the fix and removing sensitive data. Apple rules are as of October 2026.

Where do I get an iOS crash report?

Where the report comes from decides how fast you get it. Pick a source based on whether the phone is with you.

Source How to get it When to use it
A test phone connected to your computer List with kxdevice crash list, download with kxdevice crash pull Crashes during your own testing. Fastest
A user’s or tester’s phone On the phone, Settings > Privacy & Security > Analytics & Improvements > Analytics Data, find the report and share it with you The person isn’t with you
TestFlight The TestFlight page in App Store Connect, under Feedback > Crashes Beta testing, when testers submit crash feedback
App Store release The Crashes organizer in Xcode Live apps, for users who share analytics data

Test phones: download with kxdevice

Connect the phone to your computer with a cable, list the reports, then download them to a local folder. PATTERN is a file name wildcard. Leave it out to get everything.

1kxdevice crash list MyTodo*
2kxdevice crash pull .\crashes MyTodo*

If you’d rather not remember commands, run kxdevice web and open http://localhost:8780 in your browser to view crash reports on a web page. See the kxdevice command reference.

When the app crashes while you debug with F5, the debugger stops at the failing location first, and the system hasn’t written a report yet. For a full report, type detach in the Debug Console to let the app finish crashing, then download it.

User phones: share from Analytics Data

Ask the person to open Settings > Privacy & Security > Analytics & Improvements > Analytics Data on their iPhone. Crash report names start with the app’s executable name, followed by the date and time. Reports for apps the system ended because of low memory start with JetsamEvent. They tap the report and use the share button to send it to you, for example as an email attachment.

TestFlight and the App Store

Crashes from TestFlight testers are shared with you automatically, regardless of the analytics setting on their phone. Open the app in App Store Connect, go to the TestFlight page, click Crashes under Feedback in the sidebar, open an entry and use the download button in the top-right corner to get a .zip with the crash report and the tester’s comments. Crash reports can be downloaded for 120 days, and feedback for apps ended for being unresponsive doesn’t include a report. For how testers submit feedback, see TestFlight beta testing.

Crashes from release builds are collected by Apple into the Crashes organizer in Xcode, and include only users who share analytics data. Apple notes that watchdog timeouts, excessive memory use (Jetsam), overheating and invalid code signatures don’t appear in the Crashes organizer, so get those from the phone directly. See Apple’s Acquiring crash reports and diagnostic logs.

Which fields in an .ips file matter?

Since iOS 15, crash reports are JSON files with the .ips extension, which open in any text editor. Each file holds two JSON objects. The first line is metadata, and a bug_type of 309 means it’s a crash report. The report body starts on the second line.

 1{"app_name":"MyTodo","app_version":"1.2.0","build_version":"15","bug_type":"309","bundleID":"com.example.mytodo","os_version":"iPhone OS 18.6 (22G86)","name":"MyTodo"}
 2{
 3  "modelCode" : "iPhone14,5",
 4  "exception" : {"type":"EXC_BREAKPOINT","signal":"SIGTRAP","codes":"0x0000000000000001, 0x0000000102a3c1f4"},
 5  "termination" : {"namespace":"SIGNAL","code":5,"indicator":"Trace/BPT trap: 5"},
 6  "faultingThread" : 0,
 7  "threads" : [
 8    {"triggered":true,"queue":"com.apple.main-thread","frames":[
 9      {"imageIndex":0,"imageOffset":49652,"symbol":"TodoStore.toggle(id:)","symbolLocation":120,"sourceFile":"TodoStore.swift","sourceLine":15}
10    ]}
11  ],
12  "usedImages" : [
13    {"name":"MyTodo","uuid":"0b5c6f2e-1111-2222-3333-444455556666","base":4339204096}
14  ]
15}

This is a trimmed example. Real reports also contain every thread, the registers and hundreds of system libraries. Numbers in the JSON are decimal, so convert values like code and addresses to hexadecimal. For example, 2343432205 is 0x8badf00d.

These fields decide what you give the AI. The left column is the JSON key, the middle column is the name shown by tools such as Xcode and Console after translation. The AI understands both.

JSON key Translated field name What to look at
exception.type, exception.signal Exception Type The Mach exception and signal, which set the direction for troubleshooting
termination.namespace, code, indicator Termination Reason Who ended the process and why. Watchdog and background task timeouts show up here
faultingThread, threads[].triggered Triggered by Thread Which thread triggered the crash. Its call stack matters most
lastExceptionBacktrace Last Exception Backtrace Present only for uncaught Objective-C or C++ exceptions, and points at the call that threw
asi Application Specific Information Notes added by the system and libraries, such as the watchdog timeout description
usedImages[].uuid Binary Images The build UUID of each binary, used to match symbol files
bundleInfo, osVersion, modelCode Version, OS Version, Hardware Model Which app version, system version and device model

Apple’s Interpreting the JSON format of a crash report is the authoritative field reference.

Reading order

  1. Read the Exception Type and Termination Reason, and use the table in the next section to tell what kind of crash it is.
  2. If there’s a Last Exception Backtrace, read it first. This is a language exception, the real failure point is in this section, and the crashed thread only shows abort().
  3. In the crashed thread’s call stack, go down from frame 0 to the first frame that belongs to your app. The problem code is near there.
  4. If Application Specific Information has text, read it too. It often states the cause outright.

What do the common exception types mean?

Identify the crash type first, then decide what to give the AI. The table follows Apple’s Understanding the exception types in a crash report and its subpages.

What the report shows Common causes Where to look
EXC_BAD_ACCESS (SIGSEGV) or (SIGBUS) Access to an invalid address, such as a dangling pointer, a released object, a C array out of bounds or a write to read-only memory The first frame of your code on the crashed thread. Check object lifetimes, unowned, Unsafe pointers and C/C++ code
EXC_BREAKPOINT (SIGTRAP) with Termination Reason SIGNAL, Code 0x5 A Swift runtime error, such as force-unwrapping nil with !, a failed as! cast, an array index out of range, or a call to fatalError Frame 0 of the crashed thread is usually that line. Switch to if let, guard let or as?
EXC_CRASH (SIGABRT) with a Last Exception Backtrace An uncaught Objective-C or C++ exception, such as NSArray out of bounds or KVC setting a key that doesn’t exist Read the Last Exception Backtrace to find the system method that threw and your code that called it
EXC_CRASH (SIGABRT) with Exception Subtype LAUNCH_HANG An app extension took too long to initialize Check static initializers and load() in the extension
EXC_CRASH (SIGKILL) with Code 0x8badf00d The watchdog ended an unresponsive app. scene-create means the first frame wasn’t drawn in time after launch, scene-update means the main thread was too busy to update the UI in time Move synchronous networking, large JSON parsing and synchronous Core Data migrations off the main thread
EXC_CRASH (SIGKILL) with Code 0xdead10cc The app held a file lock or SQLite lock when it was suspended Request background time with beginBackgroundTask before writing to the database, and release locks before suspension
EXC_RESOURCE CPU, memory, disk writes or wakeups exceeded a system limit. The Exception Subtype says which With NON-FATAL CONDITION, the process wasn’t ended. Treat it as a warning
File name JetsamEvent_… The system was low on memory and ended apps using it. A reason of per-process-limit means the app exceeded the per-process limit, and vm-pageshortage means background memory was reclaimed for the foreground app These reports have no call stack. Find the entry in processes that has a reason, then check memory use

If the process ended in a Jetsam report isn’t your app, your crash has nothing to do with memory, and you need to find its own crash report. For checking memory, see iOS performance profiling on Windows without Xcode Instruments.

What if the report has addresses but no function names?

When your app’s frames in the call stack show only 0x… addresses, the report is unsymbolicated. Don’t hand such a report to the AI and let it guess. Addresses mean nothing to the AI, so it can only invent a plausible-sounding cause. Work through these steps instead.

  1. Reproduce in Debug. Follow the scenario from the report and press F5 with the Debug configuration. The debugger stops on the crashing line, and you can see the call stack and variables directly. For Objective-C exceptions, add an exception breakpoint as described in Debug iOS apps on Windows with LLDB, breakpoints and crash logs.
  2. Keep symbols in Release builds you test yourself. Release builds strip symbols by default. If you only need function names during your own testing, add -D STRIP_INSTALLED_PRODUCT=NO to the build.
  3. Keep the symbol files of every release build. Apple explains that a binary and its symbol file are matched by build UUID, and the same source built with a different compiler version or build settings gets a different UUID. The uuid in the report’s usedImages must match a symbol file you saved, so save one for every build you upload. You can’t rebuild later to fill the gap.
1kxbuild build .\MyTodo.xcodeproj -c Release -D STRIP_INSTALLED_PRODUCT=NO

When a report is partially symbolicated, with function names for system libraries but only addresses for your code, the system method names in the Last Exception Backtrace are often enough to tell the cause. Seeing -[__NSArrayM objectAtIndex:] tells you it’s an array out of bounds. Giving this part to the AI is still useful, but tell it “my code’s frames have no symbols”.

How do I extract the key parts for AI analysis?

A full .ips runs to thousands of lines, mostly system threads and library lists. Pasting the whole thing wastes the AI’s context and sends device information along with it. The PowerShell script below extracts only the key fields and the first 15 frames of the crashed thread. It runs in the PowerShell that comes with Windows. Save it as ipsfacts.ps1.

 1# ipsfacts.ps1: print the key parts of an .ips crash report
 2param([Parameter(Mandatory)][string]$Path, [int]$Max = 15)
 3$lines = Get-Content -LiteralPath $Path -Encoding UTF8
 4$meta = $lines[0] | ConvertFrom-Json
 5$r = ($lines[1..($lines.Count - 1)] -join "`n") | ConvertFrom-Json
 6"App: $($meta.name) $($r.bundleInfo.CFBundleShortVersionString) ($($r.bundleInfo.CFBundleVersion))"
 7"OS: $($r.osVersion.train) ($($r.osVersion.build))  Model: $($r.modelCode)"
 8"Exception Type: $($r.exception.type) ($($r.exception.signal))  Subtype: $($r.exception.subtype)"
 9"Termination Reason: $($r.termination.namespace), Code 0x{0:x}  $($r.termination.indicator)" -f [int64]$r.termination.code
10if ($r.asi) { "Application Specific Information:"; $r.asi | ConvertTo-Json -Depth 5 }
11function Show-Frames($title, $list) {
12  $title
13  $i = 0
14  foreach ($f in $list | Select-Object -First $Max) {
15    $img = $r.usedImages[$f.imageIndex].name
16    $sym = if ($f.symbol) { "$($f.symbol) + $($f.symbolLocation)" } else { "0x{0:x}" -f [int64]$f.imageOffset }
17    $src = if ($f.sourceFile) { "  ($($f.sourceFile):$($f.sourceLine))" } else { "" }
18    "{0,-3} {1,-28} {2}{3}" -f $i, $img, $sym, $src
19    $i++
20  }
21}
22if ($r.lastExceptionBacktrace) { Show-Frames "Last Exception Backtrace:" $r.lastExceptionBacktrace }
23$t = $r.threads[$r.faultingThread]
24Show-Frames "Triggered by Thread $($r.faultingThread)  $($t.queue):" $t.frames

Running it prints a few dozen lines of text that you can copy straight to the AI.

1powershell -ExecutionPolicy RemoteSigned -File .\ipsfacts.ps1 .\crashes\MyTodo-2026-10-18-203015.ips
1App: MyTodo 1.2.0 (15)
2OS: iPhone OS 18.6 (22G86)  Model: iPhone14,5
3Exception Type: EXC_BREAKPOINT (SIGTRAP)  Subtype:
4Termination Reason: SIGNAL, Code 0x5  Trace/BPT trap: 5
5Triggered by Thread 0  com.apple.main-thread:
60   MyTodo                       TodoStore.toggle(id:) + 120  (TodoStore.swift:15)
71   MyTodo                       closure #1 in ContentView.body.getter + 64  (ContentView.swift:88)
82   SwiftUI                      specialized ButtonAction.callAsFunction() + 20

If the first dozen or so frames of the crashed thread are all system libraries and none of your code shows up, extract more with -Max 40.

How should I write the prompt for the AI?

How well the AI fixes a crash depends on three things: the key parts of the report, the steps to reproduce and the relevant code. Without the steps, it can only guess the trigger. Without the code, it can only give generic advice.

 1My iOS app crashes. Analyze the cause first, then propose a fix.
 2
 3[Environment] App 1.2.0 (15), iPhone 13 (iOS 18.6), Release build installed from TestFlight.
 4[Steps to reproduce]
 51. Create two to-dos.
 62. Swipe left on the second one and delete it.
 73. Immediately tap the checkbox in front of the first one. The app crashes every time.
 8[Key parts of the crash report]
 9(Paste the output of ipsfacts.ps1)
10[Relevant code]
11(Paste the full TodoStore.swift, plus the part of ContentView.swift that calls toggle)
12
13Requirements:
14- Based on the Exception Type and the crashed thread, explain what kind of crash this is, which line it crashes on and why.
15- Change only what causes the crash. Don't refactor anything else.
16- Explain the steps I can use to verify it no longer crashes.
17- If you're unsure about something, say so. Don't guess about code I haven't given you.

With this material, the AI usually points to the force unwrap at TodoStore.swift:15. After the delete, the list still holds the old id, firstIndex returns nil, and ! triggers a Swift runtime error.

1func toggle(id: UUID) {
2    let index = items.firstIndex(where: { $0.id == id })!
3    items[index].done.toggle()
4}

A reasonable fix handles the not-found case with guard let and logs it, so you can later confirm whether that path is ever taken.

 1import os
 2
 3final class TodoStore {
 4    private let log = Logger(subsystem: "com.example.mytodo", category: "store")
 5    var items: [TodoItem] = []
 6
 7    func toggle(id: UUID) {
 8        guard let index = items.firstIndex(where: { $0.id == id }) else {
 9            log.error("toggle: to-do \(id.uuidString, privacy: .public) not found, \(self.items.count) items")
10            return
11        }
12        items[index].done.toggle()
13    }
14}

When you review the AI’s fix, also ask where the nil came from. Replacing ! with guard only stops the crash. The UI holding an id that was already deleted may be a bug in itself, so have the AI check the caller too.

A few ways to get better answers.

  • One crash at a time. When a version has several kinds of crashes, group them by Exception Type and crash location and ask about each group separately.
  • One report per location is enough. Just confirm that the first few frames of the crashed thread match.
  • For watchdog crashes, give the main thread’s stack. The crashed thread of a 0x8badf00d crash is the main thread. Include the timeout description from Application Specific Information so the AI knows whether launch was slow or the UI froze.
  • Always include the Last Exception Backtrace for language exceptions. With only the crashed thread, all the AI sees is abort().

How do I verify the AI’s fix?

The AI saying it’s fixed doesn’t count. Verify on the phone.

  1. Repeat the reproduction steps. Go through the original steps a few times in the Debug configuration, then install a Release build on the phone and repeat once more. Release turns on optimization, and some problems only appear there.
  2. Confirm the path with logging. Log at the fix point, like the log.error above. Filter by subsystem with kxdevice ostrace. If the log line appears while you go through the steps, you’ve reproduced the right path. See Read iPhone device logs with Logger and os_log.
  3. Confirm there are no new reports. After the retest, run kxdevice crash list MyTodo* again and check for new reports.
  4. Watch TestFlight. Raise the build number and upload. The TestFlight page counts sessions and crashes per build. Once the new build has run for a while and sessions add up, compare crash counts between the old and new builds.
  5. Watch intermittent crashes longer. For crashes you can’t reproduce, don’t draw conclusions right after the fix. Let testers use the new build for a few days, then check whether reports of the same kind still appear.
1kxdevice ostrace --subsystem com.example.mytodo --levels error,fault

What sensitive data should I remove first?

Crash reports contain information about the device and the user. Before you send one to a third-party AI service, check these items.

Content Where What to do
Anonymous device identifier crashReporterKey, the same value for every report from one device Delete it
Report identifiers incident_id in the metadata, incident in the body Delete them
Install paths Container folders in procPath and usedImages[].path Delete them if you don’t need them
Business data Application Specific Information and exception messages may include user input, file names or API URLs Review each one and replace with placeholders
App name and Bundle ID Metadata and body Replace them if they’re confidential

Extracting only the key parts with the script above already removes most device information, but you still need to read the exception messages and Application Specific Information yourself. When you share crash reports publicly, Apple suggests replacing the app name and Bundle ID with strings of the same length, for example MyApp with MmVvv, so alignment stays intact and the two remain distinguishable.

Two more points. iOS crash reports users send you are their data, so confirm your privacy policy allows this kind of processing before you give them to an AI. And never paste certificates, .p12 files or App Store Connect API keys to the AI along with your code.

FAQ

Where do I find crash logs on an iPhone?

On the iPhone, open Settings > Privacy & Security > Analytics & Improvements > Analytics Data. Entries starting with the app’s name are its crash reports, and entries starting with JetsamEvent are low-memory reports. Tap one and use the share button to send it. When the phone is connected to your computer, download reports directly with kxdevice crash pull.

How do I open an .ips file?

Open it in any text editor. The first line is metadata, followed by one JSON object. Focus on exception, termination, the thread in threads whose triggered is true, and lastExceptionBacktrace.

Can AI analyze a crash report without function names?

Not really. When your code shows only addresses, the AI can only guess. Reproduce the crash on the phone with the Debug configuration so the debugger stops on the crashing line, and keep the symbol files for every release build so you can restore function names by matching the UUID in the report.

What is a 0x8badf00d crash?

The watchdog ended an unresponsive app, with the exception type EXC_CRASH (SIGKILL). scene-create in the description means the first frame took too long to draw after launch, and scene-update means the main thread was too busy to update the UI in time. Move synchronous network requests and large file parsing off the main thread.

Where do I download TestFlight crash reports?

Open the app in App Store Connect, go to the TestFlight page, click Crashes under Feedback, open an entry and use the download button in the top-right corner to get a .zip with the crash report and the tester’s comments. Crash reports can be downloaded for 120 days.