{"record":{"id":"8257c441b42afa1a","repo":"crowdsecurity/crowdsec","slug":"while-opening-s-w","errorCode":null,"errorMessage":"while opening %s: %w","messagePattern":"while opening (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csplugin/broker.go","lineNumber":228,"sourceCode":"\t}\n\n\treturn false\n}\n\nfunc (pb *PluginBroker) loadConfig(path string) error {\n\tfiles, err := listFilesAtPath(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, configFilePath := range files {\n\t\tif !strings.HasSuffix(configFilePath, \".yaml\") && !strings.HasSuffix(configFilePath, \".yml\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tfin, err := os.Open(configFilePath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"while opening %s: %w\", configFilePath, err)\n\t\t}\n\n\t\tpluginConfigs, err := NewPluginConfigList(fin)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error in %s: %w\", configFilePath, err)\n\t\t}\n\n\t\tfor _, pluginConfig := range pluginConfigs {\n\t\t\tif _, ok := pb.pluginConfigByName[pluginConfig.Name]; ok {\n\t\t\t\tlog.Warningf(\"notification '%s' is defined multiple times\", pluginConfig.Name)\n\t\t\t}\n\n\t\t\tpb.pluginConfigByName[pluginConfig.Name] = pluginConfig\n\t\t\tif !pb.profilesContainPlugin(pluginConfig.Name) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csplugin/broker.go#L210-L246","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check permissions on the reported file and its parent directory: crowdsec's runtime user needs read access.","Verify the file exists (ls -l /etc/crowdsec/notifications/); remove dangling symlinks.","Fix ownership: chown root:crowdsec and chmod 640 on notification yaml files.","Remove or rename non-config leftovers if the file is genuinely not meant to be a plugin config."],"exampleFix":"// before: unreadable config\n-rw------- root root http.yaml\n// after\nchown root:crowdsec /etc/crowdsec/notifications/http.yaml && chmod 640 /etc/crowdsec/notifications/http.yaml","handlingStrategy":"validation","validationCode":"for _, f := range yamlFiles(notifDir) {\n    fi, err := os.Stat(f)\n    if err != nil || !fi.Mode().IsRegular() { continue }\n    if h, err2 := os.Open(f); err2 != nil { log.Warnf(\"unreadable %s: %v\", f, err2); continue } else { h.Close() }\n}","typeGuard":null,"tryCatchPattern":"if err := broker.Init(ctx, cfg); err != nil {\n    if strings.Contains(err.Error(), \"while opening\") {\n        // surface file path + check perms before retry\n    }\n    return err\n}","preventionTips":["Standardize notification config ownership/permissions (root:crowdsec, 0640).","Avoid symlinks in the notifications directory.","Never hand-edit configs while crowdsec is reloading them."],"tags":["filesystem","permissions","config"],"backgroundTag":"file-open-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}