charmbracelet/crush · error

failed to delete file: %w

Error message

failed to delete file: %w

What it means

For a non-recursive DeleteFile change, applyDocumentChange calls os.Remove on a single file (or empty directory); failure is wrapped with this message. Typical OS causes are ENOTEMPTY (directory not empty), ENOENT, or EACCES.

Source

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

		}
		if err := os.WriteFile(path, []byte(""), 0o644); err != nil {
			return fmt.Errorf("failed to create file: %w", err)
		}
	}

	if change.DeleteFile != nil {
		path, err := change.DeleteFile.URI.Path()
		if err != nil {
			return fmt.Errorf("invalid URI: %w", err)
		}

		if change.DeleteFile.Options != nil && change.DeleteFile.Options.Recursive {
			if err := os.RemoveAll(path); err != nil {
				return fmt.Errorf("failed to delete directory recursively: %w", err)
			}
		} else {
			if err := os.Remove(path); err != nil {
				return fmt.Errorf("failed to delete file: %w", err)
			}
		}
	}

	if change.RenameFile != nil {
		var newPath, oldPath string
		var err error

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

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

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Set Options.Recursive = true if the target is a non-empty directory.
  2. Check existence first (os.Stat) if the file may already be gone.
  3. Verify write+execute permission on the parent directory.
  4. Inspect the wrapped OS error (ENOENT/ENOTEMPTY/EACCES) to pick the right fix.

Example fix

// before
change.DeleteFile = &protocol.DeleteFile{URI: dirURI} // dir not empty
// after
change.DeleteFile = &protocol.DeleteFile{URI: dirURI, Options: &protocol.DeleteFileOptions{Recursive: true}}
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(path)
if err != nil {
    return nil // already gone
}
if info.IsDir() && entries, _ := os.ReadDir(path); len(entries) > 0 {
    recursive = true // must set DeleteFileOptions.Recursive
}

Try / catch

var rmErr *fs.PathError
if errors.As(err, &rmErr) && errors.Is(rmErr.Err, syscall.ENOTEMPTY) {
    // retry with Options.Recursive = true
}

Prevention

When it happens

Trigger: os.Remove failing because the target is a non-empty directory without Recursive option, the file does not exist, or permissions deny removal of the parent directory.

Common situations: Deleting a folder without setting Options.Recursive; two tools racing to delete the same file; removing files from a directory the user cannot write to.

Related errors


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