Skip to content

fix(react-native): explain a missing native module at import - #82

Open
NathanWalker wants to merge 2 commits into
android-react-nativefrom
fix/rn-import-without-native-module
Open

NathanWalker wants to merge 2 commits into
android-react-nativefrom
fix/rn-import-without-native-module

Conversation

@NathanWalker

@NathanWalker NathanWalker commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Important

Squash merge this PR. The first commit (31932e9) describes isAvailable() and an Android init() change, both removed after review. Use this as the squash commit message (title + body), replacing GitHub's default list of commit messages:

fix(react-native): explain a missing native module at import

Keep failing at import when NativeScriptNativeApi is not in the app binary,
but with an error that says the package cannot run in Expo Go and that a
build made before the package was added must be rebuilt, instead of React
Native's generic TurboModuleRegistry invariant.

Split out of #77 (item 7 of the "NativeScript bugs" list in ng-native/ng-native#931). Reworked after review: importing the package without its native module still fails at import, but the error now says why.

Summary

TurboModuleRegistry.getEnforcing fails with React Native's generic invariant, which doesn't say what to do. Libraries that cannot run in Expo Go also fail at import, but with a message that names Expo Go and says to rebuild. Examples are react-native-vision-camera, react-native-mmkv, Skia, Nitro and the create-react-native-library template.

 // src/NativeScriptNativeApi.ts
-export default TurboModuleRegistry.getEnforcing<Spec>('NativeScriptNativeApi');
+function loadNativeApi(): Spec {
+  const nativeApi = TurboModuleRegistry.get<Spec>('NativeScriptNativeApi');
+  if (nativeApi == null) {
+    throw new Error("@nativescript/react-native: the native module 'NativeScriptNativeApi' is not in this app binary. " +
+      'The package contains native code, so it cannot run in Expo Go: use a development build ' +
+      '(npx expo run:ios / npx expo run:android, or EAS Build). ' +
+      'If the package was added after the app was built, rebuild the app.');
+  }
+  return nativeApi;
+}
+export default loadNativeApi();

Removed after review: isAvailable() and the Android-only init() path. Android Worklets support is coming separately.

Evidence

  • @react-native/codegen's TypeScript parser (RN 0.86.3) still reads the spec: module NativeScriptNativeApi with the same six methods.
  • tsc --strict: importers see the default export as Spec, not Spec | null.
  • No other file changes. index.ts and index.d.ts match the base branch.

Merge Danger

Door: two-way

Blast Radius: the import-time error message of @nativescript/react-native

The import still throws in the same situations. Only the message changes.

- The TurboModule is looked up with TurboModuleRegistry.get, so importing
  the package in Expo Go or a build made before it was added no longer
  raises an uncatchable invariant. isAvailable() reports whether the
  module is present; init() and the other functions that need it throw
  an error saying to rebuild.
- init() no longer installs into a Worklets runtime on Android, where
  there is none, so it returns true instead of throwing a message about
  missing react-native-worklets setup. runOnUI()/installWorklets() on
  Android say they are iOS only.
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: df891a90-8cf7-47fe-80de-22cfb1a68b74

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ammarahm-ed

Copy link
Copy Markdown
Collaborator

AFIK, if someone installed the library in Expo Go where the native part is missing, throwing an error is the correct behavior and it does not need to be fixed I think.

  1. It's not possible to use nativescript in any possible way or form in Expo Go hence we should not handle the case where the native module is missing.

  2. A build made before the package was added should throw an uncatchable error if nativescript is used somehow, but i do wonder in what case that is possible.

The other change, making the worklet runtime get installed only on iOS is also not required as we will be adding support for Android in a PR soon.

Keep failing at import when NativeScriptNativeApi is not in the app
binary, but with an error that says the package cannot run in Expo Go
and that a build made before the package was added must be rebuilt,
instead of React Native's generic TurboModuleRegistry invariant.

Drop isAvailable() and the Android-specific init() path.
@NathanWalker NathanWalker changed the title fix(react-native): import without the native module; init() on Android fix(react-native): explain a missing native module at import Oct 25, 2026
@NathanWalker

Copy link
Copy Markdown
Contributor Author

Thanks, agreed on both points. I looked at what comparable libraries do. vision-camera, mmkv, Skia, Nitro and the create-react-native-library template all fail at import when their native module is missing. vision-camera and mmkv add a message that names Expo Go and says to use a development build. So this PR now does only that:

  • It still throws at import. The difference is our own message instead of React Native's TurboModuleRegistry invariant: it says the package can't run in Expo Go, to use a development build, and to rebuild if the package was added after the build.
  • isAvailable() is removed.
  • The Android init() change is removed.

index.ts and index.d.ts now match the base branch, so the diff is only NativeScriptNativeApi.ts. Commit: 31cfa36.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants