coreybutler/nvm-windows · error

failed to get relative path for %s: %v

Error message

failed to get relative path for %s: %v

What it means

Inside the copyDirContents walk callback, filepath.Rel(srcDir, srcPath) computes the destination-relative path and this error means that call failed. In practice Rel fails only when srcDir and srcPath cannot be related — one is absolute and the other relative, or a volume separator mismatch (C: vs D:) sneaks in. Within the documented flow it is near-unreachable; when seen, it indicates malformed path inputs (UNC vs drive-letter mixing, empty srcDir) rather than an environment problem.

Source

Thrown at src/upgrade/upgrade.go:972

// copyDirContents copies all the contents (files and subdirectories) of a source directory to a destination directory.
func copyDirContents(srcDir, dstDir string) error {
	// Ensure destination directory exists
	err := os.MkdirAll(dstDir, 0755)
	if err != nil {
		return fmt.Errorf("failed to create destination directory %s: %v", dstDir, err)
	}

	// Walk through the source directory recursively
	err = filepath.Walk(srcDir, func(srcPath string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("error accessing %s: %v", srcPath, err)
		}

		// Construct the corresponding path in the destination directory
		relPath, err := filepath.Rel(srcDir, srcPath)
		if err != nil {
			return fmt.Errorf("failed to get relative path for %s: %v", srcPath, err)
		}

		dstPath := filepath.Join(dstDir, relPath)

		// If it's a directory, ensure it's created in the destination
		if info.IsDir() {
			return os.MkdirAll(dstPath, info.Mode())
		}

		// If it's a file, copy it
		return copyFile(srcPath, dstPath)
	})

	return err
}

// zipDirectory zips the contents of a directory.
func zipDirectory(sourceDir, outputZip string) error {

View on GitHub (pinned to 5b18223ca1)

Solutions

  1. Normalize both srcDir and the walk root to absolute cleaned paths with filepath.Abs/filepath.Clean before walking.
  2. Avoid UNC paths for NVM_HOME; map the share to a drive letter or use a local directory.
  3. Log srcDir and the failing srcPath at error time (add them to the message) to confirm the mismatch.
  4. Retry after relocating the operation to a local filesystem path.

Example fix

// before
relPath, err := filepath.Rel(srcDir, srcPath)

// after: normalize the base once, outside the callback
srcRoot, err := filepath.Abs(srcDir)
if err != nil { return err }
...
relPath, err := filepath.Rel(srcRoot, srcPath)
if err != nil {
    return fmt.Errorf("failed to get relative path for %s under %s: %v", srcPath, srcRoot, err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Normalize the walk root once, and reject un-relatable inputs
srcRoot, err := filepath.Abs(srcDir)
if err != nil || srcRoot == "" {
    return fmt.Errorf("invalid source dir: %q", srcDir)
}
// later: filepath.Rel(srcRoot, filepath.Clean(srcPath))

Try / catch

This is a programming-error class failure: catch, include both paths in the message, and stop — retrying cannot fix mismatched path forms. Fix the caller to pass normalized absolute paths.

Prevention

When it happens

Trigger: srcDir passed as a UNC path (\\server\share) while Walk yields drive-letter paths or vice versa; srcDir empty or relative while Walk returns absolute paths; volume-relative paths (C:foo without a slash) appearing in the tree; cwd changing mid-walk.

Common situations: NVM_HOME configured as a UNC/network path so extracted paths and base path disagree; manually invoking the copy routine with mismatched path forms; exotic junction/symlink layouts inside the extracted tree.

Related errors


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