Skip to content

Throw a JS error when a sync Java TurboModule method returns a non-native map or array - #59697

Open
tomekzaw wants to merge 2 commits into
react:mainfrom
tomekzaw:fix-sync-method-return-type
Open

tomekzaw wants to merge 2 commits into
react:mainfrom
tomekzaw:fix-sync-method-return-type

Conversation

@tomekzaw

@tomekzaw tomekzaw commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

For a synchronous method that returns an object or an array, JavaTurboModule casts the result to NativeMap or NativeArray and reads its C++ part. A module can return any WritableMap/WritableArray, for example a JavaOnlyMap or JavaOnlyArray. JNI then reads an unrelated field of that object as the native pointer, and the app crashes on the JS thread with a SIGSEGV in NativeMap::consume().

This casts the result with dynamic_ref_cast instead of static_ref_cast, so a result that isn't a native map or array throws a ClassCastException, which becomes a JS error.

Changelog:

[ANDROID] [FIXED] - Throw a JS error instead of crashing when a synchronous TurboModule method returns a map or array that isn't a native one

Test Plan:

Release RNTester (./gradlew :packages:rn-tester:android:app:assembleRelease -PreactNativeArchitectures=arm64-v8a) with these temporary, uncommitted changes:

  • SampleTurboModule.getObject returns JavaOnlyMap.of("a", 1.0) and getArray returns JavaOnlyArray.of("a") when given a marker argument.
  • A Playground screen that calls them.
  • R8 turned off, because SampleTurboModule can't initialize in a minified build, which is a separate issue.

On a Galaxy A16 (Android 16):

Call main This PR
getObject returning a JavaOnlyMap SIGSEGV: #00 NativeMap::consume(), #01 JavaTurboModule::invokeJavaMethod JS error: java.lang.ClassCastException: Tried to cast from class com.facebook.react.bridge.JavaOnlyMap to com/facebook/react/bridge/NativeMap.
getArray returning a JavaOnlyArray SIGSEGV on the JS thread JS error: java.lang.ClassCastException: Tried to cast from class com.facebook.react.bridge.JavaOnlyArray to com/facebook/react/bridge/NativeArray.
getObject({a: 1, b: 'two'}), getArray([1, 'two', {three: 3}]), getConstants() Return the expected values Same values

Not run: an automated test. JavaTurboModule has no host-side tests, and Fantom doesn't load Java modules.

🤖 Generated with Claude Code

…tive map or array

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 30, 2026
@facebook-github-tools facebook-github-tools Bot added p: Software Mansion Partner: Software Mansion Partner labels Oct 30, 2026
@tomekzaw
tomekzaw marked this pull request as ready for review October 30, 2026 22:04
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 30, 2026
name_ + "." + methodName +
"() must return a native map, such as one from Arguments.createMap()");
}
auto result = jni::static_ref_cast<NativeMap::jhybridobject>(jResult);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to type-check this unconditionally, we should use dynamic_ref_cast instead. Alternatively, we could only do the type-check in debug?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to dynamic_ref_cast in 1cbf1b1. The crash happens in release builds, so I kept the check unconditional. Rechecked on a Galaxy A16: a JavaOnlyMap/JavaOnlyArray result now throws a ClassCastException as a JS error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants