denoland/deno · error · AnyError

Cannot use --watch with an npm package whose bin entry is a…

Error message

Cannot use --watch with an npm package whose bin entry is a native executable: {main_module}

What it means

Deno's --watch mode restarts a JavaScript worker on file change, so the entrypoint must be JS/TS. When the main module resolves to an npm package whose `bin` entry is a native compiled executable (detected by is_npm_native_bin in cli/tools/run/mod.rs:327), watching is impossible: Deno cannot re-execute or reload a native binary through the runtime, so it refuses up front instead of silently not reloading.

Solutions

  1. Drop --watch and run the package directly: deno run npm:<pkg> or deno x <pkg> — both execute native bins fine.
  2. If you need restart-on-change, wrap it with an external watcher that re-invokes Deno: watchexec -r -- deno x <pkg>.
  3. If the package also ships a JS entry, point the main module at that file (npm:<pkg>/bin/js-entry.js) instead of the native bin.

Example fix

# before
 deno run --watch npm:@biomejs/biome check .
 # error: Cannot use --watch with an npm package whose bin entry is a native executable...

# after — run directly, or let watchexec do the restarting
deno x @biomejs/biome check .
# or: watchexec -r --ext ts,js -- deno x @biomejs/biome check .
Defensive patterns

Strategy: validation

Validate before calling

# Before adding --watch, check what the package's bin actually is
pkg=node_modules/<pkg>
bin=$(node -p "(v => typeof v === 'string' ? v : Object.values(v)[0])(require('./' + process.argv[1] + '/package.json').bin)" "$pkg" 2>/dev/null)
file "$pkg/$bin" | grep -Eq 'ELF|Mach-O|PE32' && echo 'native bin: do NOT use --watch' || echo 'script: --watch ok'

Prevention

When it happens

Trigger: deno run --watch npm:<package> (or a watch-mode config whose main module is an npm specifier) where the package's `bin` target is a native ELF/Mach-O/PE binary, e.g. platform-specific CLIs shipped via per-OS optionalDependencies like esbuild, @biomejs/biome, or turbo.

Common situations: Porting a watch workflow from a local TS entrypoint to an npm CLI; CI scripts that reuse --watch flags mechanically; monorepos where the entry silently changes from a JS shim to a native bin after a package upgrade.

Related errors


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

Appendix: source

Thrown at cli/tools/run/mod.rs:327

      watcher_communicator.show_path_changed(changed_paths.clone());
      Ok(async move {
        let factory = CliFactory::from_flags_for_watcher(
          flags,
          watcher_communicator.clone(),
        );
        let cli_options = factory.cli_options()?;
        let main_module = cli_options.resolve_main_module()?;
        let preload_modules = cli_options.preload_modules()?;
        let require_modules = cli_options.require_modules()?;

        if main_module.scheme() == "npm" {
          set_npm_user_agent();
        }

        maybe_npm_install(&factory).await?;

        if is_npm_native_bin(&factory, main_module).await? {
          return Err(deno_core::anyhow::anyhow!(
            "Cannot use --watch with an npm package whose bin entry is a native executable: {main_module}"
          ));
        }

        let _ = watcher_communicator.watch_paths(cli_options.watch_paths());

        let mut worker = factory
          .create_cli_main_worker_factory()
          .await?
          .create_main_worker(
            mode,
            main_module.clone(),
            preload_modules,
            require_modules,
          )
          .await?;

        let exit_code = if watch_flags.hmr {

View on GitHub (pinned to 9ad36f7a2c)