coreybutler/nvm-windows · error

Unable to move directory

Error message

Unable to move directory %s to node_modules: %v

What it means

Sent (Done: true) when moveNpmErr != nil after install tried to move the freshly downloaded npm into the version's node_modules directory (the npmSourcePath rename). The version directory itself was already renamed into env.root, so node is installed but its bundled npm is missing.

Solutions

  1. Fully remove the broken install first: `nvm uninstall <version>` (or delete <NVM_HOME>\v<version>), then `nvm install <version>` again.
  2. Run the shell elevated (Administrator) so renames under the nvm root succeed.
  3. Exclude the nvm root from antivirus real-time scanning.
  4. Keep NVM_HOME on a local, non-synced disk.

Example fix

# before
nvm install 20.11.0   # retries over a half-installed v20.11.0
# after
nvm uninstall 20.11.0
nvm install 20.11.0
Defensive patterns

Strategy: fallback

Validate before calling

# bash: detect a previous partial install before reinstalling
if [ -d "$NVM_HOME/v$V/node_modules/npm" ] || [ -d "$NVM_HOME/v$V" ]; then
  nvm uninstall "$V" 2>/dev/null || rm -rf "$NVM_HOME/v$V"
fi
nvm install "$V"

Try / catch

nvm install "$V" || { nvm uninstall "$V"; nvm install "$V"; }

Prevention

When it happens

Trigger: `nvm install <version>` where moving npmSourcePath into <root>\v<version>\node_modules fails: destination exists from a previous partial install, file locked by AV/indexer, or permissions on the nvm root.

Common situations: Retrying an install that previously half-completed (leftover node_modules\npm); antivirus holding handles on freshly written files; nvm root on a network drive or synced folder with unreliable rename semantics.

Related errors


AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15). Data as JSON: /api/errors/b6bd19afb899c3a8. Report an issue: GitHub.

Appendix: source

Thrown at src/nvm.go:810

						moveNpmErr = utility.Rename(npmSourcePath, filepath.Join(root, "v"+version, "node_modules", "npm"))
						if moveNpmErr == nil {
							break
						}
					}
				}

				if err == nil && moveNpmErr == nil {
					err = utility.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
					if err != nil {
						status <- Status{Err: err}
					}
					if show_progress {
						status <- Status{Done: true}
					} else {
						status <- Status{Text: fmt.Sprintf("Installation complete. If you want to use this version, type\n\nnvm use %s", version), Done: true}
					}
				} else if moveNpmErr != nil {
					status <- Status{Err: fmt.Errorf("Unable to move directory %s to node_modules: %v", npmSourcePath, moveNpmErr), Done: true}
				} else {
					status <- Status{Err: fmt.Errorf("Failed to extract npm: %v", err), Done: true}
				}
			} else {
				err = utility.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
				if err != nil {
					status <- Status{Err: err}
				}

				npmurl := web.GetFullNpmUrl(version)
				if show_progress {
					// Send special error notification with link to npm release when it cannot be downloaded
					notify(Notification{
						Title:   "Download Failure (npm)",
						Message: fmt.Sprintf("Please download npm v%s manually and extract to %s\\v%s", version, env.root, version),
						Icon:    "error",
						Actions: []Action{
							{Type: "protocol", Label: "Manually Download", URI: npmurl},

View on GitHub (pinned to 5b18223ca1)