{"record":{"id":"2088be1029defc56","repo":"crowdsecurity/crowdsec","slug":"document-d-w","errorCode":null,"errorMessage":"document %d: %w","messagePattern":"document (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csplugin/broker.go","lineNumber":456,"sourceCode":"\tparsedConfigs := make(PluginConfigList, 0)\n\n\tdec := yaml.NewDecoder(fin)\n\tdec.SetStrict(true)\n\n\tidx := -1\n\n\tfor {\n\t\tvar pc PluginConfig\n\n\t\tidx += 1\n\n\t\terr := dec.Decode(&pc)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"document %d: %w\", idx, err)\n\t\t}\n\n\t\t// if the yaml document is empty, skip\n\t\tif reflect.DeepEqual(pc, PluginConfig{}) {\n\t\t\tcontinue\n\t\t}\n\n\t\tparsedConfigs = append(parsedConfigs, pc)\n\t}\n\n\treturn parsedConfigs, nil\n}\n\nfunc getUUID() (string, error) {\n\tuuidv4, err := uuid.NewRandom()\n\tif err != nil {\n\t\treturn \"\", err\n\t}","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csplugin/broker.go#L438-L474","documentation":"NewPluginConfigList decodes a yaml stream document-by-document with a yaml.Decoder; any Decode error other than io.EOF is wrapped as \"document %d: %w\" with the 0-based document index. It pinpoints which yaml document inside a (possibly multi-document) notification config file is malformed.","triggerScenarios":"loadConfig -> NewPluginConfigList(fin): dec.Decode returns a non-EOF error on document idx — invalid yaml syntax (tabs, bad types like a string where a list is expected) in the Nth --- separated document.","commonSituations":"Multi-document yaml where a later document has a syntax error or wrong types (e.g. timeout: soon instead of a duration); mixed content after ---; truncated file upload/edit.","solutions":["Open the reported file and inspect the Nth document after the Nth '---' separator (index is 0-based).","Fix yaml syntax there: no tabs, correct types (timeout as duration like 10s, lists as - items).","Validate the whole file with yamllint or python -c 'import yaml,sys; list(yaml.safe_load_all(open(sys.argv[1])))' file.yaml.","Remove empty/garbage trailing documents; empty PluginConfig docs are skipped but broken ones are not."],"exampleFix":"// before: document 1 has bad type\ntimeout: soon\n// after\ntimeout: 30s","handlingStrategy":"validation","validationCode":"// pre-validate multi-doc yaml\nimport \"gopkg.in/yaml.v3\"\ndec := yaml.NewDecoder(fin)\nfor i := 0; ; i++ {\n    var pc PluginConfig\n    if err := dec.Decode(&pc); err != nil { break }\n}","typeGuard":null,"tryCatchPattern":"configs, err := NewPluginConfigList(fin)\nif err != nil {\n    var docErr string\n    if _, scan := fmt.Sscanf(err.Error(), \"document %d\", new(int)); scan == nil {\n        docErr = \"check the numbered yaml document\"\n    }\n    return fmt.Errorf(\"notification config invalid (%s): %w\", docErr, err)\n}","preventionTips":["Run a yaml multi-document linter on notification configs in CI/deploy.","Keep one plugin config per --- document and avoid trailing garbage.","Use durations (30s) and lists for typed fields, never free-form strings."],"tags":["yaml","parsing","config"],"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-14T05:17:10.506Z"}