crowdsecurity/crowdsec · warning

%s is already installed at %s

Error message

%s is already installed at %s

What it means

Item.PathForInstall computes the symlink target for installing an item. If i.State.IsInstalled() is true, the item already has a local symlink, and reinstalling would overwrite/conflict, so it errors instead.

Source

Thrown at pkg/cwhub/item.go:123

	Description string   `json:"description,omitempty" yaml:"description,omitempty"`
	Content     string   `json:"content,omitempty"     yaml:"-"`
	References  []string `json:"references,omitempty"  yaml:"references,omitempty"`

	// NOTE: RemotePath could be derived from the other fields
	RemotePath string                 `json:"path,omitempty"     yaml:"path,omitempty"`    // path relative to the base URL eg. /parsers/stage/author/file.yaml
	Version    string                 `json:"version,omitempty"  yaml:"version,omitempty"` // the last available version
	Versions   map[string]ItemVersion `json:"versions,omitempty" yaml:"-"`                 // all the known versions

	// The index contains the dependencies of the "latest" version (collections only)
	Dependencies
}

// PathForInstall returns the path to use for the install symlink
// (eg. /etc/crowdsec/collections/xyz.yaml).
// Returns an error if an item is already installed or if the path goes outside of the install dir.
func (i *Item) PathForInstall() (string, error) {
	if i.State.IsInstalled() {
		return "", fmt.Errorf("%s is already installed at %s", i.FQName(), i.State.LocalPath)
	}

	p := i.Type
	if i.Stage != "" {
		p = filepath.Join(p, i.Stage)
	}

	return SafePath(i.hub.local.InstallDir, filepath.Join(p, i.FileName))
}

// PathForDownload returns the path to use to store the item's file from the hub
// (eg. /etc/crowdsec/hub/collections/author/xyz.yaml).
// Raises an error if the path goes outside of the hub dir.
func (i *Item) PathForDownload() (string, error) {
	path, err := SafePath(i.hub.local.HubDir, i.RemotePath)

	if i.State.IsDownloaded() && path != i.State.DownloadPath {
		// A hub item with the same name is at a different location.

View on GitHub (pinned to 909b515798)

Solutions

  1. Skip the install if the item is already installed (check i.State.IsInstalled() first)
  2. Use `cscli collections install <name> --force` (or the corresponding upgrade path) to overwrite
  3. Remove the existing symlink at State.LocalPath before installing
  4. Use item.Upgrade instead of Install when intending to refresh

Example fix

// before
path, err := item.PathForInstall()
// after
if !item.State.IsInstalled() {
    path, err := item.PathForInstall()
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

if item.State.IsInstalled() {
    return nil // or item.Upgrade()
}

Try / catch

if err := item.PathForInstall(); err != nil {
    if item.State.IsInstalled() {
        // already installed: skip or upgrade
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling CreateInstallLink / PathForInstall on an item whose State shows an existing local installation (LocalPath set and installed flag true).

Common situations: Running `cscli hub install` twice without --force; scripted installs that don't check installed state first; a leftover symlink from a previous install making the item look installed.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/47db6a252eb60ab6. Report an issue: GitHub.