coreybutler/nvm-windows · warning

failed to remove source: %w

Error message

failed to remove source: %w

What it means

In Rename()'s cross-volume fallback, once the source has been successfully copied to the destination, os.RemoveAll(old) deletes the original. This error means that cleanup deletion failed. Data is usually NOT lost — the copy exists at the destination — but the stale source remains and the operation is reported as failed.

Source

Thrown at src/utility/rename.go:41

	// If old is a directory, copy recursively
	if info.IsDir() {
		err = copyDir(old, new)
		if err != nil {
			return fmt.Errorf("failed to copy directory: %w", err)
		}
	} else {
		// Otherwise, copy a single file
		err = copyFile(old, new)
		if err != nil {
			return fmt.Errorf("failed to copy file: %w", err)
		}
	}

	// Remove the original source
	err = os.RemoveAll(old)
	if err != nil {
		return fmt.Errorf("failed to remove source: %w", err)
	}

	return nil
}

// copyFile copies a single file from source (old) to destination (new).
func copyFile(old, new string) error {
	srcFile, err := os.Open(old)
	if err != nil {
		return fmt.Errorf("failed to open source file: %w", err)
	}
	defer srcFile.Close()

	// Ensure destination directory exists
	destDir := filepath.Dir(new)
	err = os.MkdirAll(destDir, os.ModePerm)
	if err != nil {
		return fmt.Errorf("failed to create destination directory: %w", err)

View on GitHub (pinned to 5b18223ca1)

Solutions

  1. Since the copy already succeeded, simply delete the leftover source directory manually once no processes use it: rmdir /s /q <old>.
  2. Terminate node.exe/npm processes and re-run the original nvm command.
  3. Clear read-only attributes: attrib -r <old>\*.* /s /d, then delete.
  4. Run elevated if removal is denied by ACLs.
Defensive patterns

Strategy: fallback

Try / catch

if err := utility.Rename(old, new); err != nil {
    if strings.Contains(err.Error(), "failed to remove source") {
        // Copy already succeeded — treat as success and clean up later
        go os.RemoveAll(old)
        err = nil
    }
}

Prevention

When it happens

Trigger: utility.Rename(old, new) across volumes where the copy succeeded but the source tree cannot be removed: a file inside is open (running node.exe/npm.cmd), a read-only attribute blocks deletion, or another process (antivirus, indexer) holds a handle.

Common situations: Moving a node version while a terminal still has its npm.cmd or node.exe running; Windows Search or Defender transiently holding handles; source files marked read-only after being restored from backup.

Related errors


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