software-mansion / react-native-reanimated

React Native's Animated library reimplemented
https://docs.swmansion.com/react-native-reanimated/
MIT License
8.66k stars 1.27k forks source link

Calling `runOnJS` on a remote function marked as worklet throws "Attempted to extract from a HostObject that wasn't converted to a Shareable" #5442

Open tomekzaw opened 7 months ago

tomekzaw commented 7 months ago

Description

The following error appears when trying to call runOnJS on a function which is also marked as worklet.

ReanimatedError: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable., js engine: reanimated
Zrzut ekranu 2023-11-30 o 17 37 36

Steps to reproduce

function RemoteFunctionWorkletDemo() {
  const someFunction = (x: number) => {
    'worklet'; // this is a worklet but we will call it as a remote function
    console.log(_WORKLET, x); // _WORKLET should be false
  };

  const someWorklet = (x: number) => {
    'worklet';
    console.log(_WORKLET, x); // _WORKLET should be true
    runOnJS(someFunction)(x);
  };

  const handlePress = () => {
    runOnUI(someWorklet)(Math.random());
  };

  return <Button onPress={handlePress} title="RemoteFunctionWorkletDemo" />;
}

Snack or a link to a repository

no

Reanimated version

3.6.0

React Native version

0.72.6

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

React Native

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

iOS simulator

Device model

iPhone 15 Pro

Acknowledgements

Yes

tomekzaw commented 7 months ago

Workaround

Remove 'worklet'; directive.

 function RemoteFunctionWorkletDemo() {
   const someFunction = (x: number) => {
-    'worklet';
     console.log(_WORKLET, x); // _WORKLET should be false
   };

   const someWorklet = (x: number) => {
     'worklet';
     console.log(_WORKLET, x); // _WORKLET should be true
     runOnJS(someFunction)(x);
   };

   const handlePress = () => {
     runOnUI(someWorklet)(Math.random());
   };

   return <Button onPress={handlePress} title="RemoteFunctionWorkletDemo" />;
 }

Thanks @JDBoots for reporting this in https://github.com/software-mansion/react-native-reanimated/issues/5322#issuecomment-1833547242.

claudesortwell commented 6 months ago

Cant use workaround as it seems to be used like this in gesture handler and some other libs. Also cant really replicate it locally but users are crashing from it.

Here is my android stack trace if this helps:

Exception com.facebook.jni.CppException: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.

Error: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.
    at _scheduleOnJS (native)
    at anonymous (JavaScript:1:453)
    at anonymous (JavaScript:1:212)
    at anonymous (JavaScript:1:638)
    at handleAndFlushAnimationFrame (JavaScript:1:148)
  at com.swmansion.reanimated.nativeProxy.EventHandler.receiveEvent
  at com.swmansion.reanimated.nativeProxy.EventHandler.receiveEvent (EventHandler.java:25)
  at com.swmansion.gesturehandler.react.RNGestureHandlerStateChangeEvent.dispatch (RNGestureHandlerStateChangeEvent.kt:50)
  at com.swmansion.reanimated.NodesManager.handleEvent (NodesManager.java:327)
  at com.swmansion.reanimated.NodesManager.onEventDispatch (NodesManager.java:313)
  at com.facebook.react.uimanager.events.EventDispatcherImpl.dispatchEvent (EventDispatcherImpl.java:116)
  at com.swmansion.gesturehandler.ReactContextExtensionsKt.dispatchEvent (ReactContextExtensions.kt:9)
  at com.swmansion.gesturehandler.react.RNGestureHandlerModule.sendEventForDirectEvent (RNGestureHandlerModule.kt:605)
  at com.swmansion.gesturehandler.react.RNGestureHandlerModule.sendEventForReanimated (RNGestureHandlerModule.kt:591)
  at com.swmansion.gesturehandler.react.RNGestureHandlerModule.onStateChange (RNGestureHandlerModule.kt:543)
  at com.swmansion.gesturehandler.react.RNGestureHandlerModule.access$onStateChange (RNGestureHandlerModule.kt:49)
  at com.swmansion.gesturehandler.react.RNGestureHandlerModule$eventListener$1.onStateChange (RNGestureHandlerModule.kt:312)
  at com.swmansion.gesturehandler.core.GestureHandler.dispatchStateChange (GestureHandler.kt:84)
  at com.swmansion.gesturehandler.core.GestureHandlerOrchestrator.onHandlerStateChange (GestureHandlerOrchestrator.kt:133)
  at com.swmansion.gesturehandler.core.GestureHandler.moveToState (GestureHandler.kt:558)
  at com.swmansion.gesturehandler.core.GestureHandler.cancel (GestureHandler.kt:647)
  at com.swmansion.gesturehandler.core.GestureHandlerOrchestrator.cancelAll (GestureHandlerOrchestrator.kt:215)
  at com.swmansion.gesturehandler.core.GestureHandlerOrchestrator.onTouchEvent (GestureHandlerOrchestrator.kt:39)
  at com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper.dispatchTouchEvent (RNGestureHandlerRootHelper.kt:101)
  at com.swmansion.gesturehandler.react.RNGestureHandlerRootView.dispatchTouchEvent (RNGestureHandlerRootView.kt:36)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3286)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2990)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3286)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2990)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3286)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2990)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3286)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2990)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3286)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2990)
  at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3286)
  at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2990)
  at com.android.internal.policy.DecorView.superDispatchTouchEvent (DecorView.java:1116)
  at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent (PhoneWindow.java:1971)
  at android.app.Activity.dispatchTouchEvent (Activity.java:4388)
  at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent (WindowCallbackWrapper.java:70)
  at com.android.internal.policy.DecorView.dispatchTouchEvent (DecorView.java:1074)
  at android.view.View.dispatchPointerEvent (View.java:15803)
  at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent (ViewRootImpl.java:8153)
  at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:7877)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:7213)
  at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:7270)
  at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:7236)
  at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:7434)
  at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:7244)
  at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:7491)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:7217)
  at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:7270)
  at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:7236)
  at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:7244)
  at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:7217)
  at android.view.ViewRootImpl.deliverInputEvent (ViewRootImpl.java:10788)
  at android.view.ViewRootImpl.doProcessInputEvents (ViewRootImpl.java:10676)
  at android.view.ViewRootImpl.enqueueInputEvent (ViewRootImpl.java:10632)
  at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent (ViewRootImpl.java:10926)
  at android.view.InputEventReceiver.dispatchInputEvent (InputEventReceiver.java:285)
  at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents
  at android.view.InputEventReceiver.consumeBatchedInputEvents (InputEventReceiver.java:262)
  at android.view.ViewRootImpl.doConsumeBatchedInput (ViewRootImpl.java:10874)
  at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run (ViewRootImpl.java:11020)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1301)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1309)
  at android.view.Choreographer.doCallbacks (Choreographer.java:923)
  at android.view.Choreographer.doFrame (Choreographer.java:844)
  at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1283)
  at android.os.Handler.handleCallback (Handler.java:942)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loopOnce (Looper.java:226)
  at android.os.Looper.loop (Looper.java:313)
  at android.app.ActivityThread.main (ActivityThread.java:8762)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:604)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
claudesortwell commented 6 months ago

@tomekzaw Do you want me to post this issue in Gesture handler? Also let me know if there is anything i can help with

kslbdev commented 5 months ago

Hi @claudesortwell did you figure a workaround for Gesture handler?

ismaelsousa commented 4 months ago

I am facing the same

Fatal Exception: com.facebook.jni.CppException: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.

Error: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.
    at _scheduleOnJS (native)
    at anonymous (JavaScript:1:438)
    at anonymous (JavaScript:1:212)
    at anonymous (JavaScript:1:629)
    at handleAndFlushAnimationFrame (JavaScript:1:148)
       at com.swmansion.reanimated.nativeProxy.EventHandler.receiveEvent(EventHandler.java)
       at com.swmansion.reanimated.nativeProxy.EventHandler.receiveEvent(EventHandler.java:25)
       at com.swmansion.gesturehandler.react.RNGestureHandlerStateChangeEvent.dispatch(RNGestureHandlerStateChangeEvent.kt:42)
       at com.swmansion.reanimated.NodesManager.handleEvent(NodesManager.java:327)
       at com.swmansion.reanimated.NodesManager.onEventDispatch(NodesManager.java:313)
       at com.facebook.react.uimanager.events.EventDispatcherImpl.dispatchEvent(EventDispatcherImpl.java:116)
       at com.swmansion.gesturehandler.ReactContextExtensionsKt.dispatchEvent(ReactContextExtensions.kt:9)
       at com.swmansion.gesturehandler.react.RNGestureHandlerModule.sendEventForDirectEvent(RNGestureHandlerModule.kt:638)
       at com.swmansion.gesturehandler.react.RNGestureHandlerModule.sendEventForReanimated(RNGestureHandlerModule.kt:624)
       at com.swmansion.gesturehandler.react.RNGestureHandlerModule.onStateChange(RNGestureHandlerModule.kt:576)
       at com.swmansion.gesturehandler.react.RNGestureHandlerModule.access$onStateChange(RNGestureHandlerModule.kt:38)
       at com.swmansion.gesturehandler.react.RNGestureHandlerModule$eventListener$1.onStateChange(RNGestureHandlerModule.kt:346)
       at com.swmansion.gesturehandler.core.GestureHandler.dispatchStateChange(GestureHandler.kt:84)
       at com.swmansion.gesturehandler.core.GestureHandlerOrchestrator.onHandlerStateChange(GestureHandlerOrchestrator.kt:155)
       at com.swmansion.gesturehandler.core.GestureHandler.moveToState(GestureHandler.kt:551)
       at com.swmansion.gesturehandler.core.GestureHandler.cancel(GestureHandler.kt:640)
       at com.swmansion.gesturehandler.core.GestureHandlerOrchestrator.cancelAll(GestureHandlerOrchestrator.kt:244)
       at com.swmansion.gesturehandler.core.GestureHandlerOrchestrator.onTouchEvent(GestureHandlerOrchestrator.kt:43)
       at com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper.dispatchTouchEvent(RNGestureHandlerRootHelper.kt:97)
       at com.swmansion.gesturehandler.react.RNGestureHandlerRootView.dispatchTouchEvent(RNGestureHandlerRootView.kt:35)
       at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3286)
       at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2990)

The gesture is re-throwing the event and the reanimated is listening. I am not able to determine where this is happening

Do you know when this code is executed? @tomekzaw

link to code

 if (handler.actionType == GestureHandler.ACTION_TYPE_REANIMATED_WORKLET) {
        // Reanimated worklet
        val event = RNGestureHandlerEvent.obtain(handler, handlerFactory)
        sendEventForReanimated(event)
 }
ismaelsousa commented 4 months ago

I am facing the same

Fatal Exception: com.facebook.jni.CppException: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.

Error: Exception in HostFunction: [Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.
    at _scheduleOnJS (native)
    at anonymous (JavaScript:1:438)
    at anonymous (JavaScript:1:212)
    at anonymous (JavaScript:1:629)

Hi @claudesortwell, @kslbdev, and @tomekzaw, you are right @tomekzaw

in my case was an inline declaration of a function to run in the runOnJS

workletContext {
    runOnJS(() => onGestureCancel?.())();
}
stack trace of an app using react native and drawer library

For me was happening in the implementation of the react-native-drawer-layout while using the useAnimatedGestureHandler

For the fix just need to create the function in the JSContext

Check the official fix for this: https://github.com/react-navigation/react-navigation/commit/3cfb3e63949f0aa6f4b14db02161dd88fd10cb12?diff=unified&w=1

tomekzaw commented 4 months ago

@ismaelsousa Thanks a lot for your investigation, fixing this bug at source and letting us know here! You're a hero!

huschu commented 4 weeks ago

I get this error every time I try to use runOnJS in useAnimatedReaction or in a callback function of reanimated. Is there a way to "de-workletise" these or another workaround? I'm on 3.12.0.