crowdsecurity/crowdsec · error

while reading symlink: %w

Error message

while reading symlink: %w

What it means

After confirming the local path is a symlink, RemoveInstallLink reads the link target. If os.Readlink fails, the error is wrapped as 'while reading symlink: %w'. This is rare: it means the symlink disappeared between the stat and readlink, or the OS rejected the call.

Source

Thrown at pkg/hubops/disable.go:27

	"github.com/crowdsecurity/crowdsec/pkg/cwhub"
)

// RemoveInstallLink removes the item's symlink between the installation directory and the local hub.
func RemoveInstallLink(i *cwhub.Item) error {
	stat, err := os.Lstat(i.State.LocalPath)
	if err != nil {
		return err
	}

	// if it's managed by hub, it's a symlink to csconfig.GConfig.hub.HubDir / ...
	if stat.Mode()&os.ModeSymlink == 0 {
		return fmt.Errorf("%s isn't managed by hub", i.Name)
	}

	target, err := os.Readlink(i.State.LocalPath)
	if err != nil {
		return fmt.Errorf("while reading symlink: %w", err)
	}

	if target != i.State.DownloadPath {
		return fmt.Errorf("%s isn't managed by hub", i.Name)
	}

	if err := os.Remove(i.State.LocalPath); err != nil {
		return fmt.Errorf("while removing symlink: %w", err)
	}

	i.State.LocalPath = ""

	return nil
}

// DisableCommand uninstalls an item and its dependencies, ensuring that no
// sub-item is left in an inconsistent state.
type DisableCommand struct {

View on GitHub (pinned to 909b515798)

Solutions

  1. Ensure only one cscli process modifies the config directory at a time
  2. Re-list items ('cscli hub list') to refresh state, then retry
  3. Reinstall the item if the state is inconsistent

Example fix

// before
if err := RemoveInstallLink(item); err != nil { ... }
// after
if err := acquireConfigLock(); err != nil { return err }
defer releaseConfigLock()
if err := RemoveInstallLink(item); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

target, err := os.Readlink(item.State.LocalPath)
if err != nil { return fmt.Errorf("symlink vanished: %w", err) }

Try / catch

if err := hubops.RemoveInstallLink(item); err != nil {
    if errors.Is(err, fs.ErrNotExist) { /* refresh state and retry once */ }
    return err
}

Prevention

When it happens

Trigger: Calling RemoveInstallLink when the symlink is concurrently removed/modified, or on a filesystem that does not support readlink on that path.

Common situations: Concurrent cscli runs racing on the same config directory; broken filesystem state; the item file was deleted by another process between checks.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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