wavetermdev/waveterm · error

invalid destination path: %w

Error message

invalid destination path: %w

What it means

RenameAppFile validates the destination file name by resolving it inside the app directory before performing the rename. validateAndResolveFilePath rejects absolute paths, '..' path traversal, and any path that escapes the app directory. The library wraps that failure as "invalid destination path" so callers know the destination fileName argument, not the filesystem, is the problem.

Source

Thrown at pkg/waveappstore/waveappstore.go:395

func RenameAppFile(appId string, fromFileName string, toFileName string) error {
	if err := ValidateAppId(appId); err != nil {
		return fmt.Errorf("invalid appId: %w", err)
	}

	appDir, err := GetAppDir(appId)
	if err != nil {
		return err
	}

	fromPath, err := validateAndResolveFilePath(appDir, fromFileName)
	if err != nil {
		return fmt.Errorf("invalid source path: %w", err)
	}

	toPath, err := validateAndResolveFilePath(appDir, toFileName)
	if err != nil {
		return fmt.Errorf("invalid destination path: %w", err)
	}

	if err := os.MkdirAll(filepath.Dir(toPath), 0755); err != nil {
		return fmt.Errorf("failed to create destination directory: %w", err)
	}

	if err := os.Rename(fromPath, toPath); err != nil {
		return fmt.Errorf("failed to rename file: %w", err)
	}

	return nil
}

func FormatGoFile(appId string, fileName string) error {
	if err := ValidateAppId(appId); err != nil {
		return fmt.Errorf("invalid appId: %w", err)
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Ensure toFileName is a relative path inside the app (e.g. "subdir/main.go"), not an absolute path
  2. Strip any leading '/' and resolve/eliminate any '..' components from toFileName before calling
  3. Join the destination with GetAppDir(appId) and confirm it stays within the app directory
  4. Call validateAndResolveFilePath-equivalent logic (filepath.Clean + prefix check) client-side to pre-validate

Example fix

// before
RenameAppFile(appId, "main.go", "/tmp/newname.go")
// after
RenameAppFile(appId, "main.go", "src/newname.go")
Defensive patterns

Strategy: validation

Validate before calling

func validDestName(name string) bool {
	if filepath.IsAbs(name) {
		return false
	}
	clean := filepath.Clean(name)
	return !strings.HasPrefix(clean, "..") && !strings.Contains(clean, string(filepath.Separator)+"..")
}
if !validDestName(toFileName) {
	return errors.New("destination must be a relative path inside the app")
}

Type guard

func isRelativeInApp(appDir, name string) bool {
	if filepath.IsAbs(name) { return false }
	clean := filepath.Clean(name)
	if strings.HasPrefix(clean, "..") { return false }
	full, _ := filepath.Abs(filepath.Join(appDir, clean))
	root, _ := filepath.Abs(appDir)
	return strings.HasPrefix(full, root+string(filepath.Separator))
}

Try / catch

if err := RenameAppFile(appId, from, to); err != nil {
	if strings.Contains(err.Error(), "invalid destination path") {
		return fmt.Errorf("bad rename target %q: %w", to, err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling RenameAppFile (via RenameAppFileCommand) with a toFileName that is absolute (e.g. "/etc/passwd"), contains ".." segments (e.g. "../other/file.go"), or resolves outside ~/waveapps/<ns>/<app>.

Common situations: Users typing a destination path with leading '/' or '..' in a rename prompt; frontend code passing a full path instead of an app-relative name; path separators from Windows pasted into a rename input.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/f61a159415473e63. Report an issue: GitHub.