"Failed to load native binding" with `@node-rs/bcrypt` + Expo Router API Routes (Metro bundler)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 1.5k
- Forks
- 52
- Avg merge
- 13h 37m
- Merged PRs (30d)
- 19
Description
Companion issue (expo/expo): https://github.com/expo/expo/issues/32350
Hi, first of all, thanks for these Rust libraries! Nice performance, and good options when the main bcrypt, etc packages don't work in a particular environment.
We are trying to use @node-rs/bcrypt in Expo Router API Routes (using Metro bundler), and we're getting some output that the native binding cannot be loaded (because it's "undefined", see further below):
Android Bundled 852ms node_modules/expo-router/entry.js (1049 modules)
λ Bundled 443ms app/hash+api.ts (4 modules)
Metro error: Failed to load native binding
357 | // - The user may need to bundle the correct files
358 | // - The user may need to re-install node_modules to get new packages
> 359 | throw new Error('Failed to load native binding', { cause: loadErrors })
| ^
360 | }
361 | throw new Error(`Failed to load native binding`)
362 | }
Call Stack
factory (node_modules/@node-rs/bcrypt/binding.js:359:11)
loadModuleImplementation (node_modules/metro-runtime/src/polyfills/require.js:277:5)
guardedLoadModule (node_modules/metro-runtime/src/polyfills/require.js:184:12)
require (node_modules/metro-runtime/src/polyfills/require.js:92:7)
factory (node_modules/@node-rs/bcrypt/index.js:1:84)
loadModuleImplementation (node_modules/metro-runtime/src/polyfills/require.js:277:5)
guardedLoadModule (node_modules/metro-runtime/src/polyfills/require.js:184:12)
require (node_modules/metro-runtime/src/polyfills/require.js:92:7)
factory (app/hash+api.ts:1)
loadModuleImplementation (node_modules/metro-runtime/src/polyfills/require.js:277:5)
ERROR [SyntaxError: JSON Parse error: Unexpected character: <]
I think Metro is not logging out the error cause, so adapting the node_modules/@node-rs/bcrypt/binding.js to log out loadErrors shows that it is using "undefined" as the module specifier:
if (!nativeBinding) {
if (loadErrors.length > 0) {
// TODO Link to documentation with potential fixes
// - The package owner could build/publish bindings for this arch
// - The user may need to bundle the correct files
// - The user may need to re-install node_modules to get new packages
+ console.log(loadErrors[0])
+ console.log(loadErrors[1])
+ console.log(loadErrors[2])
+ console.log(loadErrors[3])
throw new Error('Failed to load native binding', { cause: loadErrors })
}
throw new Error(`Failed to load native binding`)
}
This is repeated 4 times:
λ LOG Error: Requiring unknown module "undefined". If you are sure the module exists, try restarting Metro. You may also want to run `yarn` or `npm install`.
at unknownModuleError (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:322:10)
at loadModuleImplementation (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:244:11)
at guardedLoadModule (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:184:12)
at require (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:92:7)
at requireNative (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/@node-rs/bcrypt/binding.js:130:16)
at factory (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/@node-rs/bcrypt/binding.js:332:17)
at loadModuleImplementation (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:277:5)
at guardedLoadModule (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:184:12)
at require (/Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/metro-runtime/src/polyfills/require.js:92:7)
at /Users/k/p/repro-expo-router-api-routes-node-rs-bcrypt/node_modules/@node-rs/bcrypt/index.js:1:84
Reproduction
Creation steps:
mkdir repro-expo-router-api-routes-node-rs-bcrypt && cd repro-expo-router-api-routes-node-rs-bcryptnpx create-expo-app@latest .rm -r ./node_modules && npm install(forEMFILEerror)- Remove extra files
- Configure
app.jsonwithexpo.web.output = "server"andexpo.plugins[0][1] = { "origin": "http://localhost:8081" } - Create a file
app/hash+api.ts, with an Expo Router API Route, usinghashSyncfrom@node-rs/bcrypt - Inside
app/(tabs)/index.tsx, add afetch()of the API Route insideuseFocusEffect - 💥
npm startand observe the error after API Route bundling
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/bcrypt/binding.js, especially requireNative and the native binding loading path, then compare it with the Metro reproduction in app/hash+api.ts and the Expo Router setup. Reproduce the failure with the linked project and inspect how Metro resolves the binding candidates. Done means the API route bundles and hashSync runs without the undefined-module or failed-native-binding errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs, rust
- Domain
- backend, build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100