crowdsecurity/crowdsec · error

while opening %s: %w

Error message

while opening %s: %w

What it means

loadConfig walks the notification config directory and opens every .yaml/.yml file with os.Open; when the OS open fails (permissions, dangling symlink, deleted mid-iteration), the path and the underlying error are wrapped as "while opening %s: %w". It means a file inside the notifications directory could not be read, not that its content is invalid (that is error in %s, 802).

Source

Thrown at pkg/csplugin/broker.go:228

	}

	return false
}

func (pb *PluginBroker) loadConfig(path string) error {
	files, err := listFilesAtPath(path)
	if err != nil {
		return err
	}

	for _, configFilePath := range files {
		if !strings.HasSuffix(configFilePath, ".yaml") && !strings.HasSuffix(configFilePath, ".yml") {
			continue
		}

		fin, err := os.Open(configFilePath)
		if err != nil {
			return fmt.Errorf("while opening %s: %w", configFilePath, err)
		}

		pluginConfigs, err := NewPluginConfigList(fin)
		if err != nil {
			return fmt.Errorf("error in %s: %w", configFilePath, err)
		}

		for _, pluginConfig := range pluginConfigs {
			if _, ok := pb.pluginConfigByName[pluginConfig.Name]; ok {
				log.Warningf("notification '%s' is defined multiple times", pluginConfig.Name)
			}

			pb.pluginConfigByName[pluginConfig.Name] = pluginConfig
			if !pb.profilesContainPlugin(pluginConfig.Name) {
				continue
			}
		}
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Check permissions on the reported file and its parent directory: crowdsec's runtime user needs read access.
  2. Verify the file exists (ls -l /etc/crowdsec/notifications/); remove dangling symlinks.
  3. Fix ownership: chown root:crowdsec and chmod 640 on notification yaml files.
  4. Remove or rename non-config leftovers if the file is genuinely not meant to be a plugin config.

Example fix

// before: unreadable config
-rw------- root root http.yaml
// after
chown root:crowdsec /etc/crowdsec/notifications/http.yaml && chmod 640 /etc/crowdsec/notifications/http.yaml
Defensive patterns

Strategy: validation

Validate before calling

for _, f := range yamlFiles(notifDir) {
    fi, err := os.Stat(f)
    if err != nil || !fi.Mode().IsRegular() { continue }
    if h, err2 := os.Open(f); err2 != nil { log.Warnf("unreadable %s: %v", f, err2); continue } else { h.Close() }
}

Try / catch

if err := broker.Init(ctx, cfg); err != nil {
    if strings.Contains(err.Error(), "while opening") {
        // surface file path + check perms before retry
    }
    return err
}

Prevention

When it happens

Trigger: PluginBroker.Init -> loadConfig when os.Open(configFilePath) returns an error: permission denied on the file, directory listed a file that vanished, or an unreadable symlink.

Common situations: Notification configs in /etc/crowdsec/notifications owned by root with 0600 while crowdsec runs as another user; config file deleted between directory listing and open; NFS/automount hiccup.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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