From d72c58ee580eff7b94456dfdcebe19fc9a9e0ec9 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Fri, 30 Oct 2026 22:32:18 +0100 Subject: [PATCH 1/2] Throw a JS error when a Java TurboModule sync method returns a non-native map or array Co-Authored-By: Claude Opus 5.5 --- .../platform/android/ReactCommon/JavaTurboModule.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp index 8cce1cf4e70..63b1dde75b7 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp @@ -893,6 +893,12 @@ jsi::Value JavaTurboModule::invokeJavaMethod( jsi::Value returnValue = jsi::Value::null(); if (returnObject != nullptr) { auto jResult = jni::adopt_local(returnObject); + if (!jResult->isInstanceOf(NativeMap::javaClassStatic())) { + throw jsi::JSError( + runtime, + name_ + "." + methodName + + "() must return a native map, such as one from Arguments.createMap()"); + } auto result = jni::static_ref_cast(jResult); returnValue = jsi::valueFromDynamic(runtime, result->cthis()->consume()); @@ -913,6 +919,12 @@ jsi::Value JavaTurboModule::invokeJavaMethod( jsi::Value returnValue = jsi::Value::null(); if (returnObject != nullptr) { auto jResult = jni::adopt_local(returnObject); + if (!jResult->isInstanceOf(NativeArray::javaClassStatic())) { + throw jsi::JSError( + runtime, + name_ + "." + methodName + + "() must return a native array, such as one from Arguments.createArray()"); + } auto result = jni::static_ref_cast(jResult); returnValue = jsi::valueFromDynamic(runtime, result->cthis()->consume()); From 1cbf1b1f326c81e0e30507b0cf04a1d2d9129bfb Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Sat, 31 Oct 2026 09:42:11 +0100 Subject: [PATCH 2/2] Type-check sync map and array results with dynamic_ref_cast Co-Authored-By: Claude Opus 5.5 --- .../android/ReactCommon/JavaTurboModule.cpp | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp index 63b1dde75b7..c4be421074c 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp @@ -892,14 +892,8 @@ jsi::Value JavaTurboModule::invokeJavaMethod( jsi::Value returnValue = jsi::Value::null(); if (returnObject != nullptr) { - auto jResult = jni::adopt_local(returnObject); - if (!jResult->isInstanceOf(NativeMap::javaClassStatic())) { - throw jsi::JSError( - runtime, - name_ + "." + methodName + - "() must return a native map, such as one from Arguments.createMap()"); - } - auto result = jni::static_ref_cast(jResult); + auto result = jni::dynamic_ref_cast( + jni::adopt_local(returnObject)); returnValue = jsi::valueFromDynamic(runtime, result->cthis()->consume()); } @@ -918,14 +912,8 @@ jsi::Value JavaTurboModule::invokeJavaMethod( jsi::Value returnValue = jsi::Value::null(); if (returnObject != nullptr) { - auto jResult = jni::adopt_local(returnObject); - if (!jResult->isInstanceOf(NativeArray::javaClassStatic())) { - throw jsi::JSError( - runtime, - name_ + "." + methodName + - "() must return a native array, such as one from Arguments.createArray()"); - } - auto result = jni::static_ref_cast(jResult); + auto result = jni::dynamic_ref_cast( + jni::adopt_local(returnObject)); returnValue = jsi::valueFromDynamic(runtime, result->cthis()->consume()); }