Is there an existing issue for this?
This issue exists in the latest npm version
Current Behavior
Under the linked install strategy, packages that use the napi-postinstall "check" pattern for platform-specific native bindings (e.g. unrs-resolver, and by extension oxc/rolldown/rspack-family packages) run a postinstall like:
unrs-resolver@1.11.1 postinstall: napi-postinstall unrs-resolver 1.11.1 check
napi-postinstall then reports the already-installed binding as missing and tries to re-install it:
[napi-postinstall@0.3.4] Failed to find package "@unrs/resolver-binding-darwin-arm64" on the file system
[napi-postinstall@0.3.4] Trying to install package "@unrs/resolver-binding-darwin-arm64" using npm
[napi-postinstall@0.3.4] Failed to install package ... Cannot find module 'unrs-resolver/package.json'
[napi-postinstall@0.3.4] Trying to download "https://<registry>/@unrs/resolver-binding-darwin-arm64/-/...tgz"
npm error Failed to install package "@unrs/resolver-binding-darwin-arm64": Server responded with 418
npm error command failed
npm error command sh -c napi-postinstall unrs-resolver 1.11.1 check
On a registry that serves the binding the re-download silently succeeds (wasteful but non-fatal). On a restricted registry/proxy that does not serve platform binding tarballs (here the proxy returns HTTP 418) the install fails.
The same dependency installs cleanly under the hoisted strategy: there the platform binding is hoisted to a top-level node_modules/@unrs/... location that napi-postinstall can resolve, so the check passes silently and no re-download is attempted.
Expected Behavior
A package's optional platform binding that npm has already installed and linked should be discoverable by that package's own install script under the linked strategy, exactly as under the hoisted strategy — without napi-postinstall deciding it is missing and attempting a re-download.
Steps To Reproduce
REPRO=/tmp/linked-napi-repro
rm -rf "$REPRO" && mkdir -p "$REPRO" && cd "$REPRO"
cat > package.json << 'EOF'
{
"name": "x",
"version": "1.0.0",
"dependencies": { "unrs-resolver": "1.11.1" },
"allowScripts": { "unrs-resolver": true }
}
EOF
# Linked: the postinstall runs, napi-postinstall cannot resolve the installed binding.
npm install --install-strategy=linked --foreground-scripts --no-audit --no-fund
# -> "[napi-postinstall] Trying to install package "@unrs/resolver-binding-darwin-arm64" using npm"
# Prove it directly against the completed store (not an ordering issue):
PKG=$(ls -d node_modules/.store/unrs-resolver@*/node_modules/unrs-resolver)
( cd "$PKG" && node ../.bin/napi-postinstall unrs-resolver 1.11.1 check )
# -> "Failed to find package "@unrs/resolver-binding-darwin-arm64" on the file system"
# Hoisted: binding is hoisted to top-level, check passes silently, no re-download.
rm -rf node_modules package-lock.json
npm install --install-strategy=hoisted --foreground-scripts --no-audit --no-fund
ls -d node_modules/@unrs/resolver-binding-darwin-arm64 # present at top level
The re-download is fatal only when the configured registry refuses the binding tarball (e.g. a proxy returning HTTP 418); on a registry that serves it the install completes after a redundant download.
Notes on when the postinstall runs:
- On npm 11 (
allow-scripts permissive by default) the dependency script runs automatically, so a plain npm install --install-strategy=linked hits this.
- On npm 12 (
allow-scripts restrictive by default) dependency scripts are blocked unless listed in allowScripts, which is why the failure surfaces on 11 by default and only with an allowScripts entry on 12.
Environment
- npm: 11.17.0 (fails by default) and 12.0.0-pre.0 (fails with an
allowScripts entry for the package)
- Node.js: v24.15.0
- OS Name: Darwin 25.5.0 (macOS, arm64)
- System Model Name: Mac17,6
- Relevant config:
install-strategy = linked
Is there an existing issue for this?
This issue exists in the latest npm version
Current Behavior
Under the linked install strategy, packages that use the
napi-postinstall"check" pattern for platform-specific native bindings (e.g.unrs-resolver, and by extension oxc/rolldown/rspack-family packages) run apostinstalllike:napi-postinstallthen reports the already-installed binding as missing and tries to re-install it:On a registry that serves the binding the re-download silently succeeds (wasteful but non-fatal). On a restricted registry/proxy that does not serve platform binding tarballs (here the proxy returns HTTP 418) the install fails.
The same dependency installs cleanly under the hoisted strategy: there the platform binding is hoisted to a top-level
node_modules/@unrs/...location thatnapi-postinstallcan resolve, so the check passes silently and no re-download is attempted.Expected Behavior
A package's optional platform binding that npm has already installed and linked should be discoverable by that package's own install script under the linked strategy, exactly as under the hoisted strategy — without
napi-postinstalldeciding it is missing and attempting a re-download.Steps To Reproduce
The re-download is fatal only when the configured registry refuses the binding tarball (e.g. a proxy returning HTTP 418); on a registry that serves it the install completes after a redundant download.
Notes on when the
postinstallruns:allow-scriptspermissive by default) the dependency script runs automatically, so a plainnpm install --install-strategy=linkedhits this.allow-scriptsrestrictive by default) dependency scripts are blocked unless listed inallowScripts, which is why the failure surfaces on 11 by default and only with anallowScriptsentry on 12.Environment
allowScriptsentry for the package)install-strategy = linked