tauri-apps/tauri · error · Error
Failed to load native binding
Error message
Failed to load native binding
What it means
This is the terminal failure of the NAPI-RS loader inside @tauri-apps/cli: after the whole platform/arch chain ran, the module-level nativeBinding is still falsy while loadErrors is empty, so no more specific error can be reported. Unlike its sibling 'Cannot find native binding' error, it carries no cause chain, which itself signals that no load attempt recorded a failure (e.g. an unhandled platform combination or a require path that silently yielded nothing).
Source
Thrown at packages/cli/index.js:590
}
}
if (!nativeBinding) {
if (loadErrors.length > 0) {
const error = new Error(
`Cannot find native binding. ` +
`npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
)
// assign instead of the `new Error(message, { cause })` options form,
// which Node < 16.9 silently ignores
error.cause = loadErrors.reduce((err, cur) => {
cur.cause = err
return cur
})
throw error
}
throw new Error(`Failed to load native binding`)
}
module.exports = nativeBinding
module.exports.logError = nativeBinding.logError
module.exports.run = nativeBinding.run
View on GitHub (pinned to 2f1cd75b0f)
Solutions
- Reproduce standalone: node -e "require('@tauri-apps/cli')" to see the raw failure outside your toolchain
- Clean install: remove node_modules and lockfile, then npm install
- Confirm the platform is supported: node -p "process.platform + ' ' + process.arch" against the loader's supported matrix; if unsupported, use the WASI build (NAPI_RS_FORCE_WASI=1) or run the CLI via cargo/rustup instead
- If a bundler is involved, add @tauri-apps/cli to externals/node_modules lists so its require is untouched
- Report upstream with the standalone repro if the platform is listed as supported
Example fix
// before (bundling the CLI)
import { run } from '@tauri-apps/cli' // loader shimmed -> 'Failed to load native binding'
// after (webpack.config.js)
module.exports = { externals: { '@tauri-apps/cli': 'commonjs @tauri-apps/cli' } } Defensive patterns
Strategy: try-catch
Validate before calling
const fs = require('fs')
// preflight: a platform-specific binding should exist before require
const local = `cli.${process.platform}-${process.arch}${isMusl() ? '-musl' : '-gnu'}.node`
if (!fs.existsSync(require.resolve('@tauri-apps/cli/' + local))) {
process.env.NAPI_RS_FORCE_WASI = '1' // opt into the wasm32-wasi fallback
} Try / catch
try {
const cli = require('@tauri-apps/cli')
} catch (e) {
if (/Failed to load native binding/.test(e.message)) {
// fallback: WASI build, or shell out to a rustup-installed `tauri`
const { execSync } = require('child_process')
execSync('tauri ' + process.argv.slice(2).join(' '), { stdio: 'inherit' })
} else throw e
} Prevention
- Preflight require('@tauri-apps/cli') as its own CI step so failures are obvious and early
- Mark @tauri-apps/cli as external in bundlers (webpack externals, esbuild --external) so its require chain stays intact
- On unusual platforms set NAPI_RS_FORCE_WASI=1 deliberately to use the WASI binding
- Keep node_modules and lockfile in sync with the CLI version
When it happens
Trigger: Requiring '@tauri-apps/cli' on a platform/arch combination the loader's if/else chain does not actually attempt a load for, or in environments where require is shimmed (Electron sandbox, bundlers) so attempts neither succeed nor throw; also reachable in the WASI force path when errors are only conditionally pushed to loadErrors.
Common situations: Exotic or brand-new platform/runtime combos the generated loader predates; bundlers (webpack/esbuild) rewriting dynamic requires; patched or forked cli packages; corrupted installs where module resolution returns a falsy module.
Related errors
AI-assisted analysis of tauri-apps/tauri@2f1cd75b0f (2026-08-16).
Data as JSON: /api/errors/10a978dfbb25127f.
Report an issue: GitHub.