Skip to content

plugins:install/uninstall/update fail with false "does not exist in the registry" on Windows when Node.js is installed under a path containing a space (e.g. default C:\Program Files\nodejs) #1387

Description

@AliaksandrPatapeika

Describe the bug

On Windows, when Node.js is installed in the default location (C:\Program Files\nodejs\node.exe — the standard path used by the official Windows installer), every command that shells out to npm (plugins:install, plugins:uninstall, plugins:update) fails with a misleading error:

CLIError: <package> does not exist in the registry.

This happens even for packages that genuinely exist and are installable via a normal npm view <package> in the same shell. The real failure has nothing to do with the registry — it's a broken subprocess spawn caused by the unescaped space in process.execPath.

Root cause

In lib/spawn.js, modulePath is set to process.execPath (added between 5.4.86 and 5.5.0), and the child process is spawned with windowsVerbatimArguments: true and no shell:

if (modulePath.endsWith('.js')) {
    args.unshift(`"${modulePath}"`);
    modulePath = process.execPath; // e.g. "C:\Program Files\nodejs\node.exe"
}
...
cpSpawn(modulePath, args, { cwd, env, stdio: 'pipe', windowsVerbatimArguments: true, ... })

Because windowsVerbatimArguments: true disables Node's automatic quoting of the executable path, and process.execPath contains a space (Program Files), Windows misparses the command line. Running with DEBUG=@oclif/plugin-plugins* shows the spawned process actually receives a garbled relative path:

node:internal/modules/cjs/loader:1503
  throw err;
Error: Cannot find module 'C:\Users\<user>\AppData\Local\<cli>\Files\nodejs\node.exe'

i.e. the exe path got split at the space, and Files\nodejs\node.exe was passed as a relative script argument (resolved against the child's cwd). The npm subprocess exits with code 1, Plugins.npmHasPackage catches this and reports the package as not found in the registry — masking the real error.

Comparing with 5.4.86 (last known-good version), lib/spawn.js used the bare command name instead of the absolute exec path:

if (process.platform === 'win32' && modulePath.endsWith('.js')) {
    args.unshift(`"${modulePath}"`);
    modulePath = 'node'; // resolved via PATH, no spaces, no ambiguity
}

This avoided the issue entirely, since node (no path) has no spaces to misparse.

To Reproduce

  1. On Windows, with Node.js installed via the official installer (default path C:\Program Files\nodejs\).
  2. Use any oclif CLI depending on @oclif/plugin-plugins@^5.5.0.
  3. Run DEBUG=@oclif/plugin-plugins* your-cli plugins:install <any-real-package>.
  4. Observe the CLIError <package> does not exist in the registry., and in the debug output, the internal Cannot find module '...\Files\nodejs\node.exe' error from the spawned process.

Expected behavior

plugins:install/uninstall/update should work regardless of whether Node.js is installed under a path containing spaces.

Environment

  • OS: Windows
  • @oclif/plugin-plugins: 5.5.0, 5.5.1 (regression); 5.4.86 (last known-good)
  • Node.js: installed at default path C:\Program Files\nodejs\node.exe

Suggested fix

Either revert to using the bare 'node' command (as in 5.4.86) on Windows, or properly quote modulePath before spawning, or drop windowsVerbatimArguments: true when the file path may contain spaces.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions