Skip to content

[v3] iOS SIGABRT crash: RNGestureHandlerRegistry tries to attach already-dropped handler during pager-view teardown (Fabric / New Architecture) #4031

@petrikjan

Description

@petrikjan

Description

When navigating back from a screen that contains react-native-pager-view (via @react-navigation/material-top-tabs) with gesture handlers registered by child components (e.g. react-native-draggable-flatlist), the app crashes with SIGABRT on iOS.

The crash occurs in RNGestureHandlerRegistry.m inside attachHandlerWithTag:toView:withActionType:withHostDetector:. During the pager-view teardown, UIKit reshuffles the view hierarchy, which triggers RNGestureHandlerDetector.willMoveToWindow:. When the detector's view is temporarily re-added to a window during teardown, the willMoveToWindow: handler tries to re-attach gesture handlers that have already been dropped from the registry, resulting in a crash.

In RNGH v2 this code path did not exist — RNGestureHandlerDetector is new in v3.

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: SIGNAL 6 Abort trap: 6

Thread 0 Crashed:
...
4  RNGestureHandler  -[RNGestureHandlerRegistry attachHandlerWithTag:toView:withActionType:withHostDetector:]
                     (RNGestureHandlerRegistry.m:41)
5  RNGestureHandler  -[RNGestureHandlerDetector attachHandlers:actionType:viewTag:attachedHandlers:]
6  RNGestureHandler  -[RNGestureHandlerDetector willMoveToWindow:]
7  UIKitCore          -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:]
...
13 PagerView         -[RCTPagerViewComponentView unmountChildComponentView:index:]
14 PagerView         -[RCTPagerViewComponentView goTo:animated:]
15 PagerView         -[RCTPagerViewComponentView setPagerViewControllers]

Root cause analysis
In RNGestureHandlerDetector.mm, the willMoveToWindow: method (line ~46) is called when UIKit moves views between windows during teardown. When newWindow != nil (view temporarily re-entering a window), the detector calls attachHandlers:actionType:viewTag:attachedHandlers:, which calls RNGestureHandlerRegistry.attachHandlerWithTag:toView:withActionType:withHostDetector:.

At this point, the gesture handlers referenced by props.handlerTags have already been dropped from the _handlers dictionary via dropHandlerWithTag:, so the lookup returns nil. In the original code, this triggered an RCTAssert that caused the SIGABRT.

Note: PR #3247 fixed a similar issue in RNGestureHandlerManager.mm for the dispatch_after retry path (StrictMode), but did not fix this separate code path in RNGestureHandlerRegistry.m / RNGestureHandlerDetector.mm.

Workaround
Replace the RCTAssert in RNGestureHandlerRegistry.m attachHandlerWithTag:toView:withActionType:withHostDetector: with a nil-check + early return:

- (void)attachHandlerWithTag:(NSNumber *)handlerTag
                      toView:(RNGHUIView *)view
              withActionType:(RNGestureHandlerActionType)actionType
            withHostDetector:(nullable RNGHUIView *)hostDetector
{
  RNGestureHandler *handler = _handlers[handlerTag];
  if (handler == nil) {
    return;  // Handler was already dropped — safe to skip
  }
  // ... rest of method
}

Steps to reproduce

  1. Create a screen using createMaterialTopTabNavigator (backed by react-native-pager-view)
  2. In one of the tab screens, use a component that registers gesture handlers (e.g. react-native-draggable-flatlist or any GestureDetector)
  3. Navigate to this screen
  4. Press back / navigate away from the screen
  5. App crashes with SIGABRT

A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.

Gesture Handler version

3.0.0-beta.2

React Native version

0.84.1

Platforms

iOS

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

New Architecture (Fabric)

Build type

Debug mode

Device

iOS simulator

Device model

No response

Acknowledgements

Yes

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions