
Mobile AR Crash Debugging: ARKit & ARCore Guide
Augmented reality has graduated from a novelty to a production-critical feature in mobile apps. From virtual try-ons in e-commerce to real-time navigation overlays and immersive gaming, AR experiences now ship to hundreds of millions of devices. But with that scale comes a brutal reality: mobile AR crash debugging introduces failure modes that standard crash reporting tools were never designed to handle. When your app simultaneously manages a camera pipeline, a 3D rendering engine, sensor fusion from the IMU and LiDAR, and a user-facing UI — all within a mobile thermal and memory budget — things break in ways that defy conventional debugging wisdom.
This guide covers the most common AR crash patterns across Apple's ARKit and Google's ARCore, explains why they happen, and provides practical debugging strategies you can ship today. Whether you are building with RealityKit, SceneKit, Unity, or raw ARCore, the failure patterns share a common root: resource contention across camera, GPU, and CPU in a real-time pipeline.
The AR Crash Landscape: Why AR Apps Fail Differently
Standard mobile app crashes typically follow predictable patterns: null pointer dereferences, out-of-bounds array access, or unhandled network errors. AR apps add three additional dimensions of failure that compound one another.
First, there is the camera pipeline. On iOS, ARKit internally manages an AVCaptureSession that demands exclusive camera access. On Android, ARCore uses the Camera2 API with similar exclusivity constraints. If another component in your app — or even a system service — attempts to access the camera simultaneously, the AR session can fail silently or crash outright. According to Apple's ARKit documentation, the session state machine transitions through .notAvailable, .limited, and .failed states, each carrying distinct error codes that developers frequently fail to inspect.
Second is the 3D rendering layer. ARKit renders through Metal on iOS, while ARCore supports both OpenGL ES and Vulkan on Android. A GPU context loss — triggered by backgrounding, a system overlay, or excessive draw calls — can corrupt the rendering pipeline and produce a crash that appears as a generic SIGSEGV or SIGABRT in your crash dashboard. The Metal Best Practices guide warns that attempting to enqueue commands on a lost device is undefined behavior.
Third is sensor fusion. AR relies on tight coupling between the camera, gyroscope, accelerometer, and (on newer devices) the LiDAR scanner. When any sensor returns degraded data — due to rapid motion, low light, or hardware faults — the tracking system can enter an unrecoverable state. Google's ARCore troubleshooting documentation notes that tracking failures are the most common source of AR session disruptions on Android.
These three systems run concurrently, sharing device memory and thermal headroom. A spike in GPU memory allocation for texture loading can trigger a system-level memory kill, while the AR session continues to hold camera buffers that the OS cannot reclaim. This is the fundamental reason AR crash debugging demands specialized tooling and workflows.
ARKit Crash Debugging: iOS AR Failure Patterns
On iOS, the central abstraction for AR is ARSession. Understanding its state machine is the single most important step in preventing ARKit crashes. The session can be in one of four states: .normal, .notAvailable, .limited, or .failed. Most crashes occur when code assumes .normal and does not handle interruptions.
The most common ARKit crash trigger is camera access conflicts. If your app initializes both a standalone AVCaptureSession for custom camera features and an ARKit session, the second session will fail with ARSession.Error.cameraUnauthorized. Worse, if a system service like FaceTime or the Camera app claims the camera mid-session, ARKit delivers an interruption callback but does not guarantee your rendering loop will stop cleanly. Developers frequently crash by continuing to submit frames to Metal after the session has been interrupted.
A defensive interruption handler should immediately pause the scene view, clear all child nodes from the scene root, and then inspect the ARSession.Error code to log the specific failure reason. The four most critical error codes are cameraUnauthorized (camera access revoked mid-session by system), sensorUnavailable (required hardware sensor became unavailable), sensorFailed (sensor hardware failure), and worldTrackingFailed (insufficient visual features in the environment). Every handler must include @unknown default to catch future error codes Apple may add.
Another major crash source is ARConfiguration validation. Developers often ship a configuration that requests features unavailable on the user's device — such as requesting .sceneReconstruction on an iPhone without a LiDAR scanner. ARKit's isSupported property on ARConfiguration should be checked before every session run, but many teams skip this in production builds, leading to crashes that only manifest on older hardware.
Memory pressure from AR frame retention is a particularly insidious problem. Each ARFrame contains a capturedImage (CVPixelBuffer), a depth map, and optionally a scene depth buffer and a point cloud. If you retain frames in a processing queue without releasing them, you will exhaust the device's memory budget within seconds. Apple instruments show that a single full-resolution AR frame with depth data can consume 15–25 MB — holding just 40 frames fills a gigabyte of memory.
RealityKit and SceneKit Crash Patterns
RealityKit, Apple's higher-level AR framework, introduces its own failure modes. Entity anchoring — the process of attaching a 3D model to a real-world surface — can fail silently when the anchor's isAnchored property never transitions to true. Developers who trigger animations or physics simulations on unanchored entities encounter EXC_BAD_ACCESS crashes because the underlying transform data is invalid.
The ARView lifecycle is another common source of crashes. If a view controller containing an ARView is dismissed while a gesture recognizer callback is still processing, the ARView delegate may fire on a deallocated object. Always nil out delegates during teardown — specifically set arView.session.delegate to nil and call arView.scene.removeAll() inside the view controller's deinit to break retain cycles before the ARView is fully deallocated.
SceneKit-based AR apps (ARSCNView) face additional risks from offscreen rendering. When a SCNRenderer is configured for high-resolution offscreen captures — common in AR screenshot or recording features — it allocates a secondary Metal texture that doubles the GPU memory footprint. If the device is already near its memory limit from the AR session, this secondary allocation triggers a jetsam event that kills the entire app process. For detailed coverage of broader camera-related crashes beyond AR, see our Mobile Camera & Media Crash Debugging Guide.
ARCore Crash Debugging: Android AR Failure Patterns
On Android, ARCore manages its session through the ArSession native object, which wraps both the camera subsystem and the SLAM (Simultaneous Localization and Mapping) engine. Unlike ARKit's straightforward state machine, ARCore's availability follows a multi-step path through ARCoreAvailability, which must be checked at startup.
The most common ARCore production crash is a missing Google Play Services for AR installation. ARCore is distributed through this package rather than bundled with your APK or AAB. If the user's device lacks the package or has an outdated version, ArSession_create returns AR_ERROR_UNAVAILABLE, which many implementations fail to handle gracefully. Google's ARCore installation flow documentation provides a maybeEnableArMode() helper, but the error-handling path after a failed installation is left to the developer — and often neglected.
Camera permission races are another Android-specific AR failure. Unlike iOS, where the permission dialog is synchronous, Android's runtime permission model means your AR session might start initializing before the user grants CAMERA permission. If ArSession_resume is called before the permission is confirmed, ARCore crashes with a SecurityException that does not appear in standard ANR reports because the crash happens in native code. Always call ArCoreApk.getInstance().checkAvailability(context) and branch on the result: SUPPORTED_INSTALLED starts the session, SUPPORTED_NOT_INSTALLED triggers the ARCore installation flow, UNSUPPORTED_DEVICE_NOT_CAPABLE shows a graceful fallback UI, and UNKNOWN_ERROR logs the failure for investigation before any native AR session object is created.
GPU context loss is even more dangerous on Android than on iOS due to device fragmentation. When ARCore renders through OpenGL ES and the system reclaims the EGL context — common on devices with aggressive background process limits — the next glDrawArrays call crashes in native code with a stack trace that never reaches your Kotlin or Java exception handler. Vulkan-based ARCore rendering is more resilient to context loss but requires Android 10+ and explicit VK_ERROR_DEVICE_LOST handling, which few AR apps implement.
The Depth API, available on ARCore-supported devices with dual cameras or ToF sensors, introduces its own crash class. Calling ArFrame_acquireDepthImage on a frame where depth data is unavailable returns a null pointer that, when passed to image processing code expecting a valid buffer, produces an immediate native crash.
Cross-Platform AR Crash Debugging Workflow
Debugging AR crashes across iOS and Android requires a unified observability strategy. Standard crash reports capture the stack trace but lose the critical context: was the AR session running? What was the tracking state? Which anchor IDs were active? Building a structured breadcrumb trail answers these questions.
Instrument your AR lifecycle with custom events that a crash reporting platform like Bugspulse can attach to every crash report. At minimum, log these events:
- session_start: Timestamp, device model, AR framework version, configuration type (world tracking, face tracking, image tracking)
- session_interrupted: Reason code, current tracking state, number of active anchors
- frame_dropped: Consecutive frame drop count, current GPU memory pressure
- anchor_failed: Anchor type, attempted position, reason (if available from SDK)
- tracking_state_change: Old state → new state, timestamp delta
When a crash occurs, these breadcrumbs provide a timeline that transforms a mysterious native stack trace into a debugging narrative. You can see that tracking degraded 400ms before the crash, or that an anchor addition coincided with a GPU memory spike. For broader observability patterns that complement AR-specific debugging, our Mobile App Observability Guide covers logging, metrics, and tracing strategies in depth.
Memory Management in AR Applications
AR memory management deserves separate attention because it spans both CPU and GPU allocations. On iOS, each ARFrame holds multiple Metal textures: the camera image, the depth map, the scene reconstruction mesh, and the point cloud. These textures are backed by IOSurface buffers that the kernel cannot page out. When your app retains even a handful of frames — for example, to run a custom ML inference pipeline on sequential depth data — you risk triggering a jetsam event that kills the process without a crash report.
On Android, the situation is compounded by the garbage collector. ARCore's native ArFrame objects wrap memory that the Java/Kotlin GC cannot see. A common pattern is retaining Frame objects in a Kotlin collection for post-processing, while the native heap grows unchecked because the GC only tracks the small Java wrapper. Use Frame.close() or rely on use blocks to release native memory immediately. Our Mobile App OOM Crash Debugging Guide covers general memory kill patterns that apply equally to AR applications.
AR Crash Prevention: Pre-Launch Checklist
Before shipping an AR feature, verify these guardrails are in place:
- Camera permission handling with a graceful fallback UI — never assume the camera is available
- AR session availability check before any configuration is applied (
ARConfiguration.isSupportedon iOS,ARCoreApk.checkAvailabilityon Android) - Device capability probing — check for LiDAR, Depth API, or scene understanding before requesting those features
- Thermal state monitoring — degrade AR quality (lower frame rate, reduce mesh detail, pause scene reconstruction) when
ProcessInfo.processInfo.thermalStateexceeds.seriouson iOS orPowerManager.isPowerSaveModetriggers on Android - Progressive complexity — start the AR session with minimal features (basic world tracking) and escalate to plane detection, scene reconstruction, and face tracking only after confirming stability
Real-World AR Crash Scenarios
Scenario 1: Foldable device mode transitions. On foldable Android devices, transitioning from folded to unfolded mode triggers a configuration change that recreates the Activity. If the ARCore session is not properly paused in onPause() and resumed in onResume(), the new Activity's rendering surface is not yet connected when ArSession_resume attempts to bind the camera. Result: native crash in libarcore_sdk_c.so.
Scenario 2: Background AR anchor persistence. iOS apps that attempt to save ARWorldMap data when entering the background have a 5-second window before the system suspends the process. If the world map serialization exceeds this window — common for scenes with many anchors — the watchdog terminates the app with 0x8badf00d. The solution is to serialize anchors incrementally and checkpoint progress.
Scenario 3: Multi-camera AR deadlock. Apps that use both the front-facing TrueDepth camera (for face tracking) and the rear camera (for world tracking) simultaneously on iOS create a deadlock on the camera hardware resource. ARKit internally serializes camera access, but user-level code that wraps both sessions in the same dispatch queue can deadlock the queue, freezing the app and triggering a watchdog termination.
Augmented reality is one of the most demanding workloads a mobile device can run, and debugging AR crashes requires understanding the full stack from camera firmware to GPU command buffers. By instrumenting your AR sessions with structured breadcrumbs, handling every session state transition defensively, and monitoring memory across both CPU and GPU allocations, you can ship AR features that stay stable at scale.
Ready to bring AR-aware crash reporting to your mobile app? Sign up at app.bugspulse.com/register and start capturing the AR session context you need to debug the crashes other tools miss.