Commit 67a44165dbc for nodejs
commit 67a44165dbc46b912f1b3b4c0ca3346f9b6a1765
Author: Alexey Karimov <krassx@gmail.com>
Date: Mon Sep 21 17:37:14 2026 +0500
node-api: do not crash on module version mismatch
`node_napi_env__::New()` returns nullptr after throwing when an add-on
declares a Node-API version this binary does not support, but
`napi_module_register_by_symbol()` dereferenced the result without
checking it. Loading such an add-on segfaulted instead of surfacing the
error the version check had already produced, so `require()` could not
catch it.
Reproduced on v20.x, v22.x, v24.x and v26.8.2 with a ten-line add-on
whose only distinguishing content is a NAPI_VERSION above
NODE_API_SUPPORTED_VERSION_MAX. `main`, `v22.x-staging` and
`v24.x-staging` all lack the check.
The error path had no test coverage: the message text appears in exactly
one file in the repository, `src/node_api.cc`. A test is added next to
`test_null_init`, which covers the sibling early return in the same
function.
Prepared with assistance from a closed-source coding agent, named in the
pull request description. The design, review and validation are my own:
I verified the fix and the test against a local build, including
removing the four added lines and relinking to confirm the test fails
without them.
Refs: https://github.com/nodejs/node/issues/57233
Signed-off-by: Alexey Karimov <krassx@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66019
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
diff --git a/src/node_api.cc b/src/node_api.cc
index e0e7cca2a4b..40bdf143a98 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -770,6 +770,8 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
// Create a new napi_env for this specific module.
napi_env env =
node_napi_env__::New(context, module_filename, module_api_version);
+ // `module_api_version` is not supported.
+ if (env == nullptr) return;
napi_value _exports = nullptr;
env->CallIntoModule([&](napi_env env) {
diff --git a/test/node-api/test_module_version_mismatch/binding.gyp b/test/node-api/test_module_version_mismatch/binding.gyp
new file mode 100644
index 00000000000..e87600d8fa4
--- /dev/null
+++ b/test/node-api/test_module_version_mismatch/binding.gyp
@@ -0,0 +1,12 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'test_module_version_mismatch',
+ 'sources': [ 'test_module_version_mismatch.c' ],
+ # One below NAPI_VERSION_EXPERIMENTAL, so it is always above
+ # NODE_API_SUPPORTED_VERSION_MAX and never becomes a real version, but is
+ # not the experimental value the version check deliberately allows.
+ 'defines': [ 'NAPI_VERSION=2147483646' ]
+ }
+ ]
+}
diff --git a/test/node-api/test_module_version_mismatch/test.js b/test/node-api/test_module_version_mismatch/test.js
new file mode 100644
index 00000000000..1881c69c0e2
--- /dev/null
+++ b/test/node-api/test_module_version_mismatch/test.js
@@ -0,0 +1,10 @@
+'use strict';
+const common = require('../../common');
+const assert = require('assert');
+
+// An add-on that requires a newer Node-API version than this binary supports
+// must be rejected with an error that `require()` can catch, rather than
+// crashing the process.
+assert.throws(
+ () => require(`./build/${common.buildType}/test_module_version_mismatch`),
+ /requires Node-API version 2147483646, but this version of Node\.js only supports version \d+ add-ons\./);
diff --git a/test/node-api/test_module_version_mismatch/test_module_version_mismatch.c b/test/node-api/test_module_version_mismatch/test_module_version_mismatch.c
new file mode 100644
index 00000000000..63027b705b2
--- /dev/null
+++ b/test/node-api/test_module_version_mismatch/test_module_version_mismatch.c
@@ -0,0 +1,7 @@
+#include <node_api.h>
+
+// This add-on declares a Node-API version that no build supports, so loading it
+// must fail with an error -- not a crash.
+NAPI_MODULE_INIT() {
+ return exports;
+}