coreybutler/nvm-windows · error

failed to stat source: %w

Error message

failed to stat source: %w

What it means

Rename() in src/utility/rename.go falls back to copy-then-delete when source and destination are on different volumes (os.Rename cannot cross drives). This error means os.Stat on the source path failed, so the function could not even determine whether it is copying a file or a directory. The wrapped error is a *PathError naming the exact cause (not exist, permission denied, etc.).

Source

Thrown at src/utility/rename.go:21

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
)

func Rename(old, new string) error {
	old_drive := filepath.VolumeName(old)
	new_drive := filepath.VolumeName(new)

	if old_drive == new_drive {
		return os.Rename(old, new)
	}

	// Get file or directory info
	info, err := os.Stat(old)
	if err != nil {
		return fmt.Errorf("failed to stat source: %w", err)
	}

	// 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)

View on GitHub (pinned to 5b18223ca1)

Solutions

  1. Check the wrapped *PathError in the message — if it says 'The system cannot find the file specified', re-create or re-select the source version before renaming.
  2. Verify the source path exists with dir/exist checks before invoking Rename in a cross-volume scenario.
  3. Run from an elevated prompt if the message shows 'Access is denied'.
  4. Enable Windows long-path support (registry LongPathsEnabled) if the source path exceeds 260 characters.

Example fix

// before
info, err := os.Stat(old)
if err != nil {
    return fmt.Errorf("failed to stat source: %w", err)
}

// after: give a clearer message with the offending path
info, err := os.Stat(old)
if err != nil {
    return fmt.Errorf("failed to stat source %q before cross-volume move: %w", old, err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight check before cross-volume rename
func RenameChecked(old, new string) error {
    if _, err := os.Lstat(old); err != nil {
        return fmt.Errorf("source missing before rename: %w", err)
    }
    return utility.Rename(old, new)
}

Try / catch

if err := utility.Rename(old, new); err != nil {
    if os.IsNotExist(errors.Unwrap(err)) {
        // source vanished — re-select/reinstall the version
    }
    return err
}

Prevention

When it happens

Trigger: Calling utility.Rename(old, new) where filepath.VolumeName(old) != filepath.VolumeName(new) (e.g. C: to D:) and 'old' does not exist, is a dangling symlink, or is unreadable by the current user.

Common situations: nvm-windows 'nvm install'/'nvm use' moving node versions across drives when the symlinked version directory was removed manually; source path mistyped or deleted by an earlier failed operation; permission or long-path (MAX_PATH) issues on Windows.

Related errors


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