Blue Triangle Help Center
Auto Light Dark
Auto Light Dark

Handling Mobile App Crashes and Stack Traces: iOS

Introduction

The Blue Triangle SDK captures and reports crashes and errors to help correlate user-experience issues with business impact. Because of this, you may see Blue Triangle SDK methods appear in a crash stack trace. This does not necessarily mean the SDK caused the crash—only that it detected the crash and was in the call chain when it reported it.


Example: UI Event Interception

To track user interactions such as taps, the Blue Triangle SDK intercepts UI events before they reach the application own code. This technique is common across analytics and monitoring SDKs.

As a result, if your app crashes during a user interaction—such as a tap—the SDK may appear in the stack trace even when the root cause is entirely within your app.

Consider the following example, where tapping a button triggers an exception:

private lazy var checkoutButton: UIButton = {
   let action = UIAction(title: "Checkout") { [weak self] _ in
       // This will crash because the array is empty
       NSArray().object(at: 99)
   }
   return UIButton(primaryAction: action)
}()

When the user taps this button, the app will crash inside the button’s action. However, because the SDK intercepts the tap to record it, the crash stack trace will show SDK methods above the line where the exception occurred.


Sample Stack Trace

Below is an example crash log from Xcode. The crash originates in RootViewController within the app code, while the SDK appears higher in the stack due to intercepting the event:

0   CoreFoundation                	       0x1804f39dc __exceptionPreprocess + 160
1   libobjc.A.dylib               	       0x18009c084 objc_exception_throw + 72
2   CoreFoundation                	       0x1803bb2e8 -[__NSArray0 objectEnumerator] + 0
3   Example-UIKit                 	       0x1007a0124 specialized RootViewController.causeNSException() + 64 (RootViewController.swift:177)
4   Example-UIKit                 	       0x10079e8c0 closure #1 in closure #1 in RootViewController.crashButton.getter + 60
5   UIKitCore                     	       0x1851aea08 0x185156000 + 363016
6   UIKitCore                     	       0x1861b0fcc -[UIAction performWithSender:target:] + 104
7   UIKitCore                     	       0x185ae7e6c -[UIControl _sendActionsForEvents:withEvent:] + 284
8   UIKitCore                     	       0x185ae464c -[UIButton _sendActionsForEvents:withEvent:] + 200
9   UIKitCore                     	       0x185ae7ed0 -[UIControl _sendActionsForEvents:withEvent:] + 384
10  UIKitCore                     	       0x185ae464c -[UIButton sendActionsForEvents:withEvent:] + 200
11  UIKitCore                     	       0x185ae6aec -[UIControl touchesEnded:withEvent:] + 428
12  UIKitCore                     	       0x186299fe4 -[UIWindow sendTouchesForEvent:] + 976
13  UIKitCore                     	       0x18629b3e4 -[UIWindow sendEvent:] + 2812
14  UIKitCore                     	       0x186279714 -[UIApplication sendEvent:] + 376
15  Example-UIKit                 	       0x100804148 UIApplication.swizzled_sendEvent(:) + 56 (UIApplication+Utils.swift:62)
16  Example-UIKit                 	       0x100804544 @objc UIApplication.swizzled_sendEvent(:) + 52
17  UIKitCore                     	       0x18630dc6c __dispatchPreprocessedEventFromEventQueue + 1184
18  UIKitCore                     	       0x186310920 __processEventQueue + 4800
19  UIKitCore                     	       0x186308ecc updateCycleEntry + 168
20  UIKitCore                     	       0x185773878 _UIUpdateSequenceRunNext + 120
21  UIKitCore                     	       0x18617ec90 schedulerStepScheduledMainSectionContinue + 56
22  UpdateCycle                   	       0x2509462b4 UC::DriverCore::continueProcessing() + 80
23  CoreFoundation                	       0x1804114ac __CFMachPortPerform + 164
24  CoreFoundation                	       0x18044dbe0 

Best Practices: Determining Whether a Crash Originates from the SDK or the App

When the crash is likely to originate in the Blue Triangle SDK

A crash can potentially be attributed to the BlueTriangle SDK if the initial frames of the crash’s stack trace include the name BlueTriangle or reference any BlueTriangle classes—such as BTTimer, ANRWatchdog, BTTTimerManager, or BTTScreenTracker.

Example:

Crashed: com.apple.root.utility-qos
0  libobjc.A.dylib               objc_retain_x0 + 16
1  libobjc.A.dylib               objc_retain + 16
2  YourApp                       ANRWatchDog.makeTimerRequest(...) (BlueTriangle.swift:172)  <-- ROOT CAUSE
3  YourApp                       closure #1 in ANRWatchDog.uploadReports(...)
4  YourApp                       thunk for @escaping @callee_guaranteed () -> ()
5  libdispatch.dylib             _dispatch_c

To determine whether a crash originated from our SDK, locate the thread labeled “Crashed” in the stack trace. Review the first several frames beneath it. If any of them reference BlueTriangle or its classes, then the crash originated from the BlueTriangle SDK.

When the crash is unlikely to originate in Blue Triangle SDK

A crash is not caused by the BlueTriangle SDK when the top frames of the “Crashed” thread point to your app’s code or another third-party library, and BlueTriangle only appears deeper in the stack trace. In these cases, BlueTriangle is simply part of the call flow—not the source of the crash.

Example:

-[__NSArray0 objectAtIndex:]: index 99 beyond bounds for empty array
0   CoreFoundation                 ... + 1155276
1   libobjc.A.dylib                objc_exception_throw + 88
2   CoreFoundation                 ... + 1167232
3   Example-UIKit.debug.dylib      RootViewController.causeNSException(...) + 80
4   Example-UIKit.debug.dylib      RootViewController.checkoutButton(...) + 160
...
15  Example-UIKit.debug.dylib      UIApplication.BlueTriangle.swizzled_sendEvent + 2676
16  Example-UIKit.debug.dylib      UIApplication.BlueTriangle.swizzled_sendEvent + 76
...

In this scenario, the crash originates from your application logic (objectAtIndex: on an empty array). Although BlueTriangle appears later in the stack, it does not indicate an SDK-caused crash.


Summary

When investigating an app crash:

  • Start by reviewing the crash in the Error Explorer within the portal. There, you can see details such as the device, OS version, application version, and SDK version. If you have session replay enabled, you can also view the user’s actions leading up to the crash. Together, these details can help narrow down the root cause.

  • Share the crash information—including app details, the stack trace, and any other relevant context—with Blue Triangle’s customer support team for further assistance.