crowdsecurity/crowdsec · error

while creating symlink from %s to %s: %w

Error message

while creating symlink from %s to %s: %w

What it means

os.Symlink(src, dest) failed while linking the item's downloaded file (i.State.DownloadPath) into the install directory. The error names both ends of the link (src → dest) so the user can diagnose either side.

Source

Thrown at pkg/hubops/enable.go:72

		return err
	}

	destDir := filepath.Dir(dest)
	if err = os.MkdirAll(destDir, os.ModePerm); err != nil {
		return fmt.Errorf("while creating %s: %w", destDir, err)
	}

	if _, err = os.Lstat(dest); err == nil {
		// already exists
		return nil
	} else if !os.IsNotExist(err) {
		return fmt.Errorf("failed to stat %s: %w", dest, err)
	}

	src := i.State.DownloadPath

	if err = os.Symlink(src, dest); err != nil {
		return fmt.Errorf("while creating symlink from %s to %s: %w", src, dest, err)
	}

	i.State.LocalPath = dest

	return nil
}

func (c *EnableCommand) Run(_ context.Context, plan *ActionPlan) error {
	i := c.Item

	fmt.Fprintln(os.Stdout, "enabling " + colorizeItemName(i.FQName()))

	if !i.State.IsDownloaded() {
		// XXX: this a warning?
		return fmt.Errorf("can't enable %s: not downloaded", i.FQName())
	}

	if err := CreateInstallLink(i); err != nil {

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify src exists: `ls -l <src>`; re-run `cscli hub update && cscli <type> install <item>` if it's missing.
  2. Remove any existing file/symlink at dest, then retry the enable command.
  3. Ensure both paths are on the same accessible filesystem and the crowdsec user can write destDir.
  4. Avoid running concurrent cscli hub operations; retry the command once the race is resolved.

Example fix

// before: dest exists from a previous partial enable
sudo rm -f /etc/crowdsec/parsers/sudo
sudo cscli parsers enable sudo
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Lstat(dest); err == nil {
    return fmt.Errorf("destination %s already exists", dest)
}
if _, err := os.Stat(src); err != nil {
    return fmt.Errorf("download path %s missing", src)
}

Try / catch

if err := os.Symlink(src, dest); err != nil {
    if errors.Is(err, os.ErrExist) {
        os.Remove(dest)
        return os.Symlink(src, dest)
    }
    return err
}

Prevention

When it happens

Trigger: During CreateInstallLink when creating the symlink fails: dest already exists (raced with Lstat check), src (DownloadPath) doesn't exist or is on a different filesystem/snapshot, or the user lacks write permission on destDir.

Common situations: Hub data dir and /etc/crowdsec on different mounts with hardlink-only tooling assumptions; the downloaded item was cleaned up between download and enable; container volume setups with restricted symlink permissions; two cscli processes racing on the same item.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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