plandex-ai/plandex · error

error getting relative path: %s

Error message

error getting relative path: %s

What it means

When parsing `git status --porcelain` output for deleted files ('D ' lines), the code joins the repo root with the deleted path and calls filepath.Rel(currentDir, absPath) to express it relative to the current directory. This error is thrown when filepath.Rel cannot compute that relative path. filepath.Rel only fails when the two paths cannot be made relative to each other.

Source

Thrown at app/cli/fs/paths.go:76

			repoRoot := strings.TrimSpace(string(output))

			cmd = exec.Command("git", "status", "--porcelain")
			cmd.Dir = baseDir
			out, err := cmd.Output()
			if err != nil {
				errCh <- fmt.Errorf("error getting git status: %s", err)
			}

			lines := strings.Split(string(out), "\n")

			for _, line := range lines {
				line = strings.TrimSpace(line)
				if strings.HasPrefix(line, "D ") {
					path := strings.TrimSpace(line[2:])
					absPath := filepath.Join(repoRoot, path)
					relPath, err := filepath.Rel(currentDir, absPath)
					if err != nil {
						errCh <- fmt.Errorf("error getting relative path: %s", err)
						return
					}
					deletedFiles[relPath] = true
				}
			}

			errCh <- nil
		}()

		// combine `git ls-files` and `git ls-files --others --exclude-standard`
		// to get all files in the repo

		numRoutines++
		go func() {
			// get all tracked files in the repo
			cmd := exec.Command("git", "ls-files")
			cmd.Dir = baseDir
			out, err := cmd.Output()

View on GitHub (pinned to e2d772072e)

Solutions

  1. Run the tool from a directory on the same drive/volume as the repository root.
  2. Ensure currentDir (ProjectRoot) and baseDir are absolute, cleaned paths before calling GetPaths (filepath.Abs + filepath.Clean).
  3. On Windows, avoid UNC paths (\\server\share) mixed with drive-letter paths for the project.
  4. If you control the call site, guard with filepath.IsAbs checks so both inputs are absolute on the same volume.

Example fix

// before
currentDir := "D:\work" // repo on C:
paths, err := fs.GetPaths(baseDir, currentDir)
// after
currentDir, _ := filepath.Abs("C:\\repo\\subdir") // same volume as repoRoot
paths, err := fs.GetPaths(baseDir, currentDir)
Defensive patterns

Strategy: validation

Validate before calling

if filepath.VolumeName(currentDir) != filepath.VolumeName(repoRoot) {
	return fmt.Errorf("currentDir and repo root must be on the same volume")
}
if _, err := filepath.Rel(currentDir, repoRoot); err != nil {
	return err
}

Type guard

func sameVolume(a, b string) bool {
	return filepath.IsAbs(a) && filepath.IsAbs(b) && filepath.VolumeName(a) == filepath.VolumeName(b)
}

Try / catch

relPath, err := filepath.Rel(currentDir, absPath)
if err != nil {
	return fmt.Errorf("cannot make %s relative to %s: %w", absPath, currentDir, err)
}

Prevention

When it happens

Trigger: currentDir and repoRoot are on different drives/volumes (Windows, e.g. C:\ vs D:\) so no relative path exists; one path is relative and the other absolute in a way filepath.Rel rejects; mixed path separators or a path with a volume name where the other has none.

Common situations: On Windows, running the CLI from a directory on a different drive than the repository root; passing currentDir with inconsistent formatting (UNC path vs drive letter); symlinked roots resolving to different volumes.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/4809e10acf4e5a54. Report an issue: GitHub.