{"record":{"id":"918a2df209630466","repo":"crowdsecurity/crowdsec","slug":"error-in-s-w","errorCode":null,"errorMessage":"error in %s: %w","messagePattern":"error in (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csplugin/broker.go","lineNumber":233,"sourceCode":"func (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}\n\n\treturn pb.verifyPluginConfigsWithProfile()\n}\n\n// checks whether every notification in profile has its own config file","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csplugin/broker.go#L215-L251","documentation":"loadConfig parses each notification yaml with NewPluginConfigList; if YAML parsing or validation fails (bad syntax, unknown fields, duplicate/invalid plugin config), the file path and error are wrapped as \"error in %s: %w\". The file opened fine but its contents are not a valid plugin notification config.","triggerScenarios":"PluginBroker.Init -> loadConfig -> NewPluginConfigList(fin) returns an error for one yaml file: invalid YAML syntax, wrong top-level structure, missing required keys like name/type/format.","commonSituations":"Hand-edited notification config with indentation mistakes; copy-pasting a config that is a single map instead of a list; typo in keys; a file in the notifications dir that is actually something else with a .yaml extension.","solutions":["Validate the yaml with a linter (yamllint) or `cscli` startup to see the line number in the wrapped error.","Ensure the file contains a valid PluginConfig structure (name, type, format) as expected by NewPluginConfigList.","Move unrelated yaml files out of the notification_dir.","Compare against a working example from the crowdsec hub (e.g. notifications/http.yaml)."],"exampleFix":"// before: invalid yaml (tab indentation)\nname: slack_default\n\ttype: slack\n// after\nname: slack_default\ntype: slack","handlingStrategy":"validation","validationCode":"// lint every yaml before deploy\nyamllint /etc/crowdsec/notifications/*.yaml","typeGuard":null,"tryCatchPattern":"if err := broker.Init(ctx, cfg); err != nil {\n    if strings.Contains(err.Error(), \"error in \") {\n        // parse the wrapped path from the message, validate that file\n    }\n    return err\n}","preventionTips":["Run yamllint (or a yaml.safe_load_all) as a deploy step for notification configs.","Keep notification yaml files 2-space indented, never tabs.","Copy from hub examples rather than writing configs from scratch."],"tags":["yaml","config","validation"],"backgroundTag":"yaml-parse-error","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"}