SIGN IN SIGN UP
denoland / deno UNCLAIMED

A modern runtime for JavaScript and TypeScript.

0 0 2 Rust

fix(ext/napi): clear error for Windows addons that link against node.exe (#34696)

## Problem

Loading uWebSockets.js (and similar prebuilt native addons) on
**Windows** fails with a cryptic error:

```
error: Uncaught (in promise) Error: This version of uWS.js supports only Node.js LTS versions 16, 18 and 20 ...
TypeError: LoadLibraryExW failed
```

The "supports only Node.js LTS" text is uWS's own fallback message; the
real error is `LoadLibraryExW failed`, which tells the user nothing
actionable.

## Root cause

uWS's prebuilt Windows `.node` (`uws_win32_x64_{108,115,127}.node`) is
**not a Node-API addon**. Inspecting its PE import table (`objdump -p`)
shows a **regular, non delay-load import of `node.exe`** that pulls in:

- raw **V8 C++ ABI** symbols (`v8::Object::New`, `HandleScope`,
`FunctionTemplate`, …)
- **Node.js internals** (`node::MakeCallback`,
`node::AddEnvironmentCleanupHook`, `node::GetCurrentEventLoop`)
- **libuv** (`uv_run`, `uv_async_init`, …) and **zlib**

The Windows loader resolves an import of `node.exe` by module name at
`LoadLibraryExW` time, so it only succeeds when the host process is
literally named `node.exe`. Loaded into `deno.exe` (or any other host —
this is also why it breaks in Node SEA, Bun and Electron), the import
can't be satisfied and the load fails.

Deno cannot make such an addon work: it doesn't (and can't) export V8's
C++ ABI, Node's internal C++ API, or a real libuv event loop. The only
correct outcome is a clear diagnostic.

## Fix

Mirrors the legacy V8/nan addon diagnostic added in #34683.

- New dependency-free, bounds-checked PE import-table reader in
`ext/napi/pe.rs`. `imports_node_executable()` parses the **regular**
import directory and checks for a `node.exe` import (case-insensitive).
It is unit-tested with a synthetic PE builder and was validated against
the real uWS binaries (output matches `objdump` exactly).
- New `NApiError::UnsupportedNodeBinaryAddon`. On Windows, when
`Library::load_with_flags` fails, the addon is inspected; if it imports
`node.exe` directly, Deno now reports:

> Cannot load native addon at <path>: it links directly against
the Node.js binary (node.exe) and relies on the V8 C++ ABI, Node.js
internals and/or libuv exported by that executable, none of which Deno
provides. Only Node-API (N-API) addons are supported. ...

**Delay-loaded** `node.exe` imports (the node-gyp default, redirected to
the host at runtime via `win_delay_load_hook`) are intentionally ignored
— those resolve against the host's exported N-API symbols and work fine
in Deno.

## Testing

- `cargo test -p deno_napi --lib pe::` — 4 unit tests
(real-binary-shaped fixtures + malformed input).
- `cargo clippy -p deno_napi --all-targets` and `cargo clippy -p
deno_napi --target x86_64-pc-windows-msvc` both clean (the new
load-failure arm is Windows-only).

Refs #25956

Closes denoland/divybot#409

---------

Co-authored-by: divybot <divybot@users.noreply.github.com>
Co-authored-by: Divy Srivastava <me@littledivy.com>
E
em committed
9d13e9d37f76d53389199c313f383597f4faecba
Parent: ccfe78a
Committed by GitHub <noreply@github.com> on 6/2/2026, 7:04:04 AM