{"record":{"id":"bc4add058e8eaf7d","repo":"crowdsecurity/crowdsec","slug":"expected-exactly-one-value-for-log-level","errorCode":null,"errorMessage":"expected exactly one value for 'log_level'","messagePattern":"expected exactly one value for 'log_level'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/acquisition/modules/journalctl/config.go","lineNumber":105,"sourceCode":"\t}\n\n\tqs := strings.TrimPrefix(dsn, \"journalctl://\")\n\tif qs == \"\" {\n\t\treturn errors.New(\"empty journalctl:// DSN\")\n\t}\n\n\tparams, err := url.ParseQuery(qs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not parse journalctl DSN: %w\", err)\n\t}\n\n\tfor key, value := range params {\n\t\tswitch key {\n\t\tcase \"filters\":\n\t\t\tfilters = append(filters, value...)\n\t\tcase \"log_level\":\n\t\t\tif len(value) != 1 {\n\t\t\t\treturn errors.New(\"expected exactly one value for 'log_level'\")\n\t\t\t}\n\n\t\t\tlvl, err := log.ParseLevel(value[0])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tlogLevel = lvl\n\t\tcase \"since\":\n\t\t\tif len(value) != 1 {\n\t\t\t\treturn errors.New(\"expected exactly one value for 'since'\")\n\t\t\t}\n\n\t\t\tsince = value[0]\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported key %s in journalctl DSN\", key)\n\t\t}\n\t}","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/acquisition/modules/journalctl/config.go#L87-L123","documentation":"In ConfigureByDSN, the log_level query parameter must be supplied exactly once because the code needs a single log.Level value. Passing it multiple times (a slice with len != 1) is ambiguous and rejected in pkg/acquisition/modules/journalctl/config.go:105 before log.ParseLevel is attempted.","triggerScenarios":"Calling ConfigureByDSN with a DSN containing log_level more than once, e.g. journalctl://?filters=x&log_level=info&log_level=debug.","commonSituations":"Query builders that append a parameter per value (array semantics) when the consumer expects a scalar; accidental duplication from merging DSN strings; shell loop appending the flag repeatedly.","solutions":["Provide log_level exactly once in the DSN: journalctl://?filters=...&log_level=info.","Deduplicate parameters before building the DSN (keep the last/intended value).","If multiple levels were intended, note journalctl DSNs accept a single log_level; move filtering to the filters parameter."],"exampleFix":"// before\njournalctl://?filters=_SYSTEMD_UNIT=ssh&log_level=info&log_level=debug\n\n// after\njournalctl://?filters=_SYSTEMD_UNIT=ssh&log_level=info","handlingStrategy":"validation","validationCode":"params := urlVals[\"log_level\"]\nif len(params) != 1 {\n    return fmt.Errorf(\"log_level must appear exactly once, got %d\", len(params))\n}\nif _, err := log.ParseLevel(params[0]); err != nil {\n    return err\n}","typeGuard":"func singleValue(vals url.Values, key string) (string, bool) {\n    v := vals[key]\n    if len(v) != 1 { return \"\", false }\n    return v[0], true\n}","tryCatchPattern":"if err := src.ConfigureByDSN(ctx, dsn); err != nil {\n    if strings.Contains(err.Error(), \"log_level\") {\n        // rebuild DSN with a single log_level value\n    }\n}","preventionTips":["Deduplicate query params before serializing the DSN.","Treat scalar DSN params as last-wins in your config builder.","Validate log_level against log.ParseLevel early."],"tags":["dsn","query-parameters","journalctl"],"backgroundTag":"invalid-query-parameter","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"}