denoland/deno · critical

Initialize libloading failed {}

Error message

Initialize libloading failed {}

What it means

On Windows, the napi_sys bindings resolve N-API function pointers from the host module at runtime. setup() must run once before any binding is used: it obtains the current module handle via libloading::os::windows::Library::this() and panics if the handle cannot be acquired, because no napi function pointer could be resolved afterwards.

Source

Thrown at libs/napi_sys/src/lib.rs:125

pub use types::*;

#[cfg(windows)]
static SETUP: Once = Once::new();

/// Loads N-API symbols from host process.
/// Must be called at least once before using any functions in bindings or
/// they will panic.
///
/// # Safety
///
/// `env` must be a valid `napi_env` for the current thread.
#[cfg(windows)]
pub unsafe fn setup() {
  SETUP.call_once(|| {
    let host = match libloading::os::windows::Library::this() {
      Ok(lib) => lib.into(),
      Err(err) => {
        panic!("Initialize libloading failed {}", err);
      }
    };

    // SAFETY: Once ensures single-threaded init; host is a valid library handle.
    unsafe {
      if let Err(err) = functions::load(&host) {
        panic!("{}", err);
      }
    }
  });
}

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Compile and load the napi glue as a real DLL on Windows so the current module handle exists
  2. Call napi_sys::setup() exactly once during module/thread initialization before touching any binding
  3. If you control the host, load the library with LoadLibrary instead of static linking so libloading can find the handle
  4. Wrap setup in std::panic::catch_unwind during bring-up to convert the abort into a reportable startup error

Example fix

// before
unsafe { napi_sys::setup(); } // panics: Initialize libloading failed ...

// after
let ok = std::panic::catch_unwind(|| unsafe { napi_sys::setup() });
if ok.is_err() {
  return Err("napi_sys setup failed: host module handle unavailable");
}
Defensive patterns

Strategy: validation

Validate before calling

// Windows-only pre-check mirroring what setup() needs to succeed
#[cfg(windows)]
fn can_resolve_host_module() -> bool {
  libloading::os::windows::Library::this().is_ok()
}

// run before any napi work
if cfg!(windows) && !can_resolve_host_module() {
  return Err("napi unavailable: host module handle cannot be resolved");
}

Try / catch

let setup = std::panic::catch_unwind(|| unsafe { napi_sys::setup() });
if setup.is_err() {
  // report a startup error instead of aborting the host process
}

Prevention

When it happens

Trigger: Calling unsafe napi_sys::setup() on Windows in a host where Library::this() fails to return the current DLL handle: the napi glue is statically linked into an executable, loaded through a custom loader that does not register a module handle, or the HMODULE context is otherwise unavailable.

Common situations: Embedding Deno's napi compatibility layer into a non-Deno host on Windows; test harnesses that load the module in unusual ways; packaging changes (static vs dynamic linking) that leave the module without a resolvable handle.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/667df12187f81b73. Report an issue: GitHub.