charmbracelet/crush · error

failed to rename file: %w

Error message

failed to rename file: %w

What it means

applyDocumentChange wraps any failure from os.Rename(oldPath, newPath) when applying an LSP RenameFile change. os.Rename fails at the OS level (not because of policy like overwrite rules), so the wrapped error carries the syscall reason. The original error is preserved via %w.

Source

Thrown at internal/lsp/util/edit.go:231

		oldPath, err = change.RenameFile.OldURI.Path()
		if err != nil {
			return err
		}

		newPath, err = change.RenameFile.NewURI.Path()
		if err != nil {
			return err
		}

		if change.RenameFile.Options != nil {
			if !change.RenameFile.Options.Overwrite {
				if _, err := os.Stat(newPath); err == nil {
					return fmt.Errorf("target file already exists and overwrite is not allowed: %s", newPath)
				}
			}
		}
		if err := os.Rename(oldPath, newPath); err != nil {
			return fmt.Errorf("failed to rename file: %w", err)
		}
	}

	if change.TextDocumentEdit != nil {
		textEdits := make([]protocol.TextEdit, len(change.TextDocumentEdit.Edits))
		for i, edit := range change.TextDocumentEdit.Edits {
			var err error
			textEdits[i], err = edit.AsTextEdit()
			if err != nil {
				return fmt.Errorf("invalid edit type: %w", err)
			}
		}
		return applyTextEdits(change.TextDocumentEdit.TextDocument.URI, textEdits, encoding)
	}

	return nil
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Read the wrapped os error (os.IsNotExist, *fs.PathError) and verify both oldPath and newPath parent directory exist before calling ApplyWorkspaceEdit
  2. Create the destination directory first (os.MkdirAll)
  3. Ensure old and new paths are on the same filesystem, or fall back to copy+delete across devices
  4. Check process permissions on both paths

Example fix

// before
err := ApplyWorkspaceEdit(edit, enc)
// after
if err := os.MkdirAll(filepath.Dir(newPath), 0o755); err != nil {
    return err
}
if _, err := os.Stat(oldPath); err != nil {
    return fmt.Errorf("source missing: %w", err)
}
err = ApplyWorkspaceEdit(edit, enc)
Defensive patterns

Strategy: validation

Validate before calling

func canRename(oldPath, newPath string) error {
    if _, err := os.Stat(oldPath); err != nil {
        return fmt.Errorf("source missing: %w", err)
    }
    if err := os.MkdirAll(filepath.Dir(newPath), 0o755); err != nil {
        return err
    }
    if of, nf := filepath.Abs(oldPath), filepath.Abs(newPath); filepath.Dir(of) != filepath.Dir(nf) {
        // warn: potential cross-device rename
    }
    return nil
}

Try / catch

var pathErr *fs.PathError
if err := ApplyWorkspaceEdit(edit, enc); err != nil {
    if errors.As(err, &pathErr) {
        log.Printf("rename failed at %s: %v", pathErr.Path, pathErr.Err)
    }
}

Prevention

When it happens

Trigger: os.Rename fails: oldPath does not exist, paths span different mount points/filesystems (EXDEV), permission denied, or newPath's parent directory does not exist.

Common situations: Renaming into a directory that was deleted or never created; moving a file across filesystems (e.g. /tmp to a mounted volume); file locked/held by another process on Windows; running without write permission on the source or destination directory.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/9692db18551c7569. Report an issue: GitHub.