Skip to content

fix: graceful degradation when native libraries are unavailable (Android)#1067

Merged
msluszniak merged 1 commit intosoftware-mansion:mainfrom
radko93:fix/graceful-degradation-missing-native-libs
Apr 14, 2026
Merged

fix: graceful degradation when native libraries are unavailable (Android)#1067
msluszniak merged 1 commit intosoftware-mansion:mainfrom
radko93:fix/graceful-degradation-missing-native-libs

Conversation

@radko93
Copy link
Copy Markdown
Contributor

@radko93 radko93 commented Apr 9, 2026

Description

On 32-bit Android devices (or devices with 64-bit CPUs running 32-bit userspace), the arm64-v8a native .so files are not found. ETInstaller.init throws RuntimeException wrapping UnsatisfiedLinkError, crashing the app at startup with no consumer-side escape hatch.

This PR adds a fallback TurboModule (ETInstallerUnavailable) whose install() returns false. RnExecutorchPackage returns it only when the native library fails to load, so JS sees a real linked module but JSI bindings are never injected. This preserves the existing linking-error Proxy for genuinely mislinked installs on supported devices.

Unsupported ABI: real module exists → install() returns false → globals not set → isAvailable is false
Supported but mislinked: module is null → existing Proxy throws linking error (unchanged)

No public API break; preserves existing mislink failure behavior. isAvailable is a new additive export.

Introduces a breaking change?

  • No

Type of change

  • Bug fix (change which fixes an issue)

Tested on

  • Android

Testing instructions

  1. Build and run on a 32-bit Android device (e.g. Galaxy A13, Moto G Play 2023)
  2. App should start without crashing
  3. isAvailable should be false
  4. Verify on a supported 64-bit device that everything works as before

Related issues

Fixes #1065

…oid)

On 32-bit Android devices (or devices with 64-bit CPUs running 32-bit
userspace), the arm64-v8a native .so files are not found and ETInstaller
throws RuntimeException wrapping UnsatisfiedLinkError, crashing the app
at startup.

Add ETInstallerUnavailable, a fallback TurboModule whose install()
returns false. RnExecutorchPackage returns it when the native library
fails to load, so JS sees a real linked module but globals are never
injected. This preserves the existing linking-error Proxy for genuinely
mislinked installs on supported devices.

Export isAvailable (based on loadExecutorchModule global presence) so
consumers can check runtime support.

No public API break; preserves existing mislink failure behavior.

Fixes software-mansion#1065
@msluszniak
Copy link
Copy Markdown
Member

Ok, it took us some time to find a suitable device to test these changes, but we will be testing in a while :))

@msluszniak
Copy link
Copy Markdown
Member

Hmm, I turned out that it will be a challenge for us. The motorola that we had is from 2016 with android 7 😅. For now, we don't have any device that has 32-bit arch to test it :/

@radko93
Copy link
Copy Markdown
Contributor Author

radko93 commented Apr 9, 2026

@msluszniak we don't have a device like that either. But a similar solution made crashes disappear at scale. There are also some devices that are 64bit but apparently run or on 32 bit. Try to Google, especially Samsung A13

@msluszniak
Copy link
Copy Markdown
Member

msluszniak commented Apr 10, 2026

Ok, I think the same applies to Motorola G04 that we have. We will test this on Monday Tuesday at the latest :))

@msluszniak msluszniak self-assigned this Apr 14, 2026
@msluszniak
Copy link
Copy Markdown
Member

Ok, I can confirm that without fix I get:

  • Fatal signal 6 (SIGABRT) — the app crashes
  • UnsatisfiedLinkError: dlopen failed: library "libexecutorch.so" not found
  • RuntimeException: Could not load native module ETInstaller
  • And eventually app crashed

with fix the UnsatisfiedLinkError is triggered aka libexecutorch.so not found. The app didn't crash.

@msluszniak msluszniak merged commit 8f20cee into software-mansion:main Apr 14, 2026
4 checks passed
@msluszniak msluszniak mentioned this pull request Apr 28, 2026
3 tasks
msluszniak added a commit that referenced this pull request Apr 29, 2026
## Summary

Patch release v0.8.4 — cherry-picks the following commits from `main`
into `release/0.8`:

- fix: graceful degradation when native libraries are unavailable
(Android) (#1067)
- fix(llm): normalize multimodal image paths to file:// URIs (#1090)
- fix(llm): auto-shape multimodal mediaPath messages in chat template
(#1089)
- feat(llm): min_p and repetition_penalty sampling, per-model defaults,
letterbox vision (#1099)

## Checklist

- [x] Commits cherry-picked from `main` in chronological order (with
`-x`)
- [x] Version bumped to `0.8.4` in
`packages/react-native-executorch/package.json`
- [x] Adapter packages (`bare-resource-fetcher`,
`expo-resource-fetcher`) untouched by cherry-picks — versions not bumped

## Docs

The unversioned doc edits that landed via the #1099 cherry-pick belong
on the "Next" version (i.e. `main`) and are already there from the
original PR. The corresponding `docs/versioned_docs/version-0.8.x/...`
updates will be done in a separate PR targeting `main` after `v0.8.4` is
published to npm — that PR will also regenerate the v0.8.x api-reference
snapshot so anchors for the new sampling fields resolve.

---------

Co-authored-by: Radek Czemerys <7029942+radko93@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Norbert Klockiewicz <Nklockiewicz12@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug fix PRs that are fixing bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App crashes on 32-bit Android devices — UnsatisfiedLinkError when native .so is missing

2 participants