neon-bindings/neon · critical

Node-API symbol has not been loaded

Error message

Node-API symbol has not been loaded

What it means

Neon's generated `sys::bindings` module declares stub `extern "C"` functions for every Node-API symbol; each stub panics with this message when called. The real symbols are only wired up at module load time by the generated registration code. Hitting a stub means the addon was loaded without its Node-API symbol table being initialized — the function you called was never resolved.

Solutions

  1. Load the addon through Node (require/import the built `.node` file) so Neon's symbol registration runs; don't call Neon code from a standalone binary or plain unit test — use integration tests via Node instead.
  2. Enable the required cargo feature (e.g. `neon = { version = "0.10", features = ["napi-8"] }`) for the Node-API functions you use, then rebuild.
  3. Ensure `neon::setup()`/generated registration is invoked exactly once at module load and wasn't removed or cfg'd out.
  4. Rebuild the addon after changing neon versions so the generated symbol table matches the linked runtime.

Example fix

// before
// Cargo.toml
neon = "0.10" // missing feature
// code uses napi-8 APIs -> symbol stub panics

// after
// Cargo.toml
neon = { version = "0.10", features = ["napi-8"] }
Defensive patterns

Strategy: validation

Validate before calling

// verify the addon loads through Node before exercising APIs
node -e "require('./index.node'); console.log('symbols loaded')"

Prevention

When it happens

Trigger: Calling a Neon API whose backing Node-API symbol was never registered — commonly because the binary was built/run as a plain executable or test instead of being loaded by Node as a native module; using a symbol gated behind a newer `napi-X` feature flag that wasn't enabled; custom `#[node_api]`/sys usage before `init` ran.

Common situations: Running Neon code in `cargo test` unit tests or a `main.rs` binary where the Node module never loads; forgetting the `napi-6`/`napi-8` cargo feature while calling an API that requires it; linking the addon into a non-Node host that skips Neon's registration step.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13). Data as JSON: /api/errors/802852e93b6d1d7f. Report an issue: GitHub.

Appendix: source

Thrown at crates/neon/src/sys/bindings/mod.rs:123

/// pub(crate) unsafe fn get_undefined(env: Env, result: *mut Value) -> Status {
///     (NAPI.get_undefined)(env, result)
/// }
/// ```
macro_rules! generate {
    (#[$extern_attr:meta] extern "C" {
        $($(#[$attr:meta])? fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
    }) => {
        struct Napi {
            $(
                $name: unsafe extern "C" fn(
                    $($param: $ptype,)*
                )$( -> $rtype)*,
            )*
        }

        #[inline(never)]
        fn panic_load<T>() -> T {
            panic!("Node-API symbol has not been loaded")
        }

        static mut NAPI: Napi = {
            $(
                unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
                    panic_load()
                }
            )*

            Napi {
                $(
                    $name,
                )*
            }
        };

        pub(super) unsafe fn load(host: &libloading::Library) {
            let print_warn = |err| eprintln!("WARN: {}", err);

View on GitHub (pinned to 38960e4381)