Summary
Fixes a fatal EXC_BREAKPOINT crash that occurs on iOS 26+ when a camera UI is presented while a session replay capture tick is in progress.
Environment
- SDK version:
swift-launchdarkly-observability 0.46.1
- iOS versions affected: 26.5, 26.5.2, 27.0 beta
- Xcode version: 26.x builds (device builds)
Crash
Fatal error: Use of unimplemented initializer 'init(layer:)' for class 'CameraUI.ModeLoupeLayer'
EXC_BREAKPOINT
Stack Trace
LaunchDarklySessionReplay.CaptureManager.frameUpdate (CaptureManager.swift:115)
LaunchDarklySessionReplay.CaptureManager.queueSnapshot (CaptureManager.swift:144)
LaunchDarklySessionReplay.ImageCaptureService.captureRawFrame (ImageCaptureService.swift:68)
LaunchDarklySessionReplay.MaskCollector.collectViewMasks (MaskCollector.swift:216)
... (MaskCollector.collectViewMasks recursive, ~20 frames) ...
LaunchDarklySessionReplay.MaskCollector.collectViewMasks (MaskCollector.swift:202)
CA::Layer::sublayers
CA::Layer::presentation_layer ← crash origin
__swift_memcpy80_8
Root Cause
On iOS 26+, when a camera picker is presented, Apple's private CameraUI framework introduces CameraUI.ChromeSwiftUIView (and its sublayers including CameraUI.ModeLoupeLayer) into the view hierarchy.
MaskCollector.collectViewMasks recursively visits the layer tree. When it reaches a parent layer whose sublayers include CameraUI.ModeLoupeLayer, accessing layer.sublayers (line 202) causes Core Animation to call CA::Layer::presentation_layer() — which internally calls init(layer:) on each sublayer to create a presentation copy. CameraUI.ModeLoupeLayer does not implement init(layer:), producing a Swift fatal error trap.
Two code paths are affected:
-
UIView path (MaskingPolicy.shouldIgnore): CameraUI.ChromeSwiftUIView is in maskiOS26ViewTypes (for masking), but NOT in any ignore/skip list, so the traversal continues into its layer subtree.
-
Pure CALayer path (MaskCollector.visit, else branch at line 184): CameraUI.ModeLoupeLayer has no backing UIView, so it enters the layer-only branch with no class name guard before the fatal layer.sublayers access.
The same crash pattern has been confirmed and fixed in other session replay SDKs (Sentry Cocoa #5647, Microsoft Clarity, Bugsee) using the same approach of skipping CameraUI.* layer subtrees.
Workaround
Disable session replay before presenting any camera UI and re-enable after dismissal, or disable it entirely until a fix is shipped.
Summary
Fixes a fatal
EXC_BREAKPOINTcrash that occurs on iOS 26+ when a camera UI is presented while a session replay capture tick is in progress.Environment
swift-launchdarkly-observability0.46.1Crash
Stack Trace
Root Cause
On iOS 26+, when a camera picker is presented, Apple's private
CameraUIframework introducesCameraUI.ChromeSwiftUIView(and its sublayers includingCameraUI.ModeLoupeLayer) into the view hierarchy.MaskCollector.collectViewMasksrecursively visits the layer tree. When it reaches a parent layer whose sublayers includeCameraUI.ModeLoupeLayer, accessinglayer.sublayers(line 202) causes Core Animation to callCA::Layer::presentation_layer()— which internally callsinit(layer:)on each sublayer to create a presentation copy.CameraUI.ModeLoupeLayerdoes not implementinit(layer:), producing a Swift fatal error trap.Two code paths are affected:
UIView path (
MaskingPolicy.shouldIgnore):CameraUI.ChromeSwiftUIViewis inmaskiOS26ViewTypes(for masking), but NOT in any ignore/skip list, so the traversal continues into its layer subtree.Pure CALayer path (
MaskCollector.visit,elsebranch at line 184):CameraUI.ModeLoupeLayerhas no backing UIView, so it enters the layer-only branch with no class name guard before the fatallayer.sublayersaccess.The same crash pattern has been confirmed and fixed in other session replay SDKs (Sentry Cocoa #5647, Microsoft Clarity, Bugsee) using the same approach of skipping
CameraUI.*layer subtrees.Workaround
Disable session replay before presenting any camera UI and re-enable after dismissal, or disable it entirely until a fix is shipped.