Skip to content

fix(cli): NAPI_RS_FORCE_WASI only activates on 'true' or 'error'#3236

Merged
Brooooooklyn merged 1 commit into
napi-rs:mainfrom
MukundaKatta:fix/napi-rs-force-wasi-truthy-string
May 26, 2026
Merged

fix(cli): NAPI_RS_FORCE_WASI only activates on 'true' or 'error'#3236
Brooooooklyn merged 1 commit into
napi-rs:mainfrom
MukundaKatta:fix/napi-rs-force-wasi-truthy-string

Conversation

@MukundaKatta

@MukundaKatta MukundaKatta commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Why

The generated native.js template treats process.env.NAPI_RS_FORCE_WASI as a plain truthy check. In JavaScript every non-empty string is truthy, so setting NAPI_RS_FORCE_WASI=false (intending to opt out) inadvertently triggers the WASI fallback — the same path that tries to require('./<pkg>.wasi.cjs') and fails with ENOENT for packages that don't ship a WASI binding.

Surfaced downstream in lancedb/lancedb#3267:

ENOENT: no such file or directory, open '.../@lancedb/lancedb/dist/lancedb.wasi.cjs'

The existing === 'error' branch at line 256 already shows the right pattern — this PR applies it consistently at the other four sites.

What

Extracts a single forceWasi boolean at the top of the generated script:

const forceWasi =
  process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error'

and uses it at all four call sites that previously did the truthy-string check. The === 'error' branch at the bottom is preserved unchanged — it already handled its value correctly.

Behavior table

NAPI_RS_FORCE_WASI Before After
unset native preferred; WASI only if native fails same
'true' forced WASI forced WASI (unchanged)
'error' forced WASI; throw if none forced WASI; throw if none (unchanged)
'false' forced WASI (bug) native preferred
'0' forced WASI (bug) native preferred
anything else forced WASI (bug) native preferred

Scope

  • Template change only (cli/src/api/templates/js-binding.ts).
  • Downstream packages pick up the fix on their next napi build.
  • No existing users who set NAPI_RS_FORCE_WASI to 'true' or 'error' are affected.
  • No behavior change when the var is unset.

Related

Summary by CodeRabbit

  • Refactor
    • Improved WASI fallback loading logic to require explicit environment variable values ('true' or 'error') instead of treating any non-empty string as truthy, resulting in more predictable behavior and clearer error handling.

The generated native.js template treated process.env.NAPI_RS_FORCE_WASI as a
plain truthy-string check. In JavaScript any non-empty string is truthy,
including 'false' and '0', so setting NAPI_RS_FORCE_WASI=false (intending
to opt out of forced WASI) inadvertently triggered the WASI fallback — the
same path that tries to load <pkg>.wasi.cjs and fails with ENOENT for
packages that don't ship a WASI binding.

Reported by lancedb/lancedb#3267, where downstream users hit:

  ENOENT: no such file or directory, open '.../@lancedb/lancedb/dist/lancedb.wasi.cjs'

This patch extracts a single `forceWasi` boolean at the top of the
generated script (equal to 'true' or 'error') and uses it consistently
at the four call sites that previously did a truthy-string check. The
existing `=== 'error'` branch at the bottom is preserved unchanged — it
already did the right thing.

This is a template change, so the fix is picked up the next time a
downstream package runs `napi build`. No behavior change for
existing users who had NAPI_RS_FORCE_WASI unset or set to 'true'/'error'.

Related: PR napi-rs#2919 added the 'error' tri-state; this patch completes
the tri-state handling by making the other two values ('true' and
everything-else) behave as documented.

Signed-off-by: Mukunda Katta <[email protected]>
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5cd8198a-fece-4fbd-965d-a5f8d697c42b

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb8eef and eb10ff2.

📒 Files selected for processing (1)
  • cli/src/api/templates/js-binding.ts

📝 Walkthrough

Walkthrough

The PR refines WASI-loading control flow in createCommonBinding by introducing an explicit forceWasi flag that only treats process.env.NAPI_RS_FORCE_WASI as 'true' or 'error', replacing the previous "any non-empty string is truthy" behavior. Error handling is now gated to the explicit 'error' value.

Changes

Cohort / File(s) Summary
WASI Fallback Control Flow
cli/src/api/templates/js-binding.ts
Introduced computed forceWasi flag that explicitly checks for 'true' or 'error' values instead of treating any non-empty string as truthy. Updated conditional logic to trigger WASI fallback on !nativeBinding || forceWasi, and confined error-throwing behavior to explicit 'error' value only.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • Brooooooklyn

Poem

🐰 A rabbit hops through env vars clear,
"True" and "error" now appear!
No guessing games with strings so vague,
The WASI fallback breaks its plague. 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main bug fix: the NAPI_RS_FORCE_WASI environment variable now only activates on explicit 'true' or 'error' values instead of treating any non-empty string as truthy.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Brooooooklyn
Brooooooklyn merged commit 030eb76 into napi-rs:main May 26, 2026
72 of 73 checks passed
wjones127 pushed a commit to lancedb/lancedb that referenced this pull request Jun 9, 2026
…e' (#3519)

## Summary

Fixes the `NAPI_RS_FORCE_WASI=false` issue by upgrading `@napi-rs/cli`
from `3.5.1` to `3.7.0`.

Closes #3267

## Root Cause

In the `native.js` loader generated by `napi build`, the check was:

```js
if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
```

In JavaScript, any non-empty string is truthy, so
`NAPI_RS_FORCE_WASI=false` (a non-empty string) inadvertently triggered
the WASI fallback path. This caused an `ENOENT` error when
`lancedb.wasi.cjs` was not present.

## Fix

`@napi-rs/[email protected]`
([napi-rs/napi-rs#3236](napi-rs/napi-rs#3236))
introduced a tri-state check in the template that generates `native.js`:

**Before (generated by @napi-rs/[email protected]):**
```js
if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
```

**After (generated by @napi-rs/[email protected]):**
```js
const forceWasi =
  process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error'

if (!nativeBinding || forceWasi) {
```

Only the literal string `'true'` (or `'error'` for strict mode) now
activates the WASI path. All other values, including `'false'`, `'0'`,
or an unset variable, behave as if WASI is not forced.

## Changes

- `nodejs/package.json`: bump `@napi-rs/cli` from `3.5.1` to `3.7.0`
- `nodejs/package-lock.json` / `nodejs/pnpm-lock.yaml`: update lock
files to match

The fix is in the upstream napi-rs tool; the generated `native.js` is
not committed to this repository and is produced at build time by `napi
build`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants