{"record":{"id":"5fa0b2de35f53c24","repo":"crowdsecurity/crowdsec","slug":"cloudwatch-path-must-contain-group-and-stream-m","errorCode":null,"errorMessage":"cloudwatch path must contain group and stream : /my/group/name:stream/name","messagePattern":"cloudwatch path must contain group and stream : /my/group/name:stream/name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/acquisition/modules/cloudwatch/config.go","lineNumber":212,"sourceCode":"\n\ts.logger.Infof(\"Adding cloudwatch group '%s' (stream:%s) to datasources\", s.Config.GroupName, targetStream)\n\n\treturn nil\n}\n\nfunc (s *Source) ConfigureByDSN(ctx context.Context, dsn string, labels map[string]string, logger *log.Entry, uuid string) error {\n\ts.logger = logger\n\n\tdsn = strings.TrimPrefix(dsn, s.GetName()+\"://\")\n\n\targs := strings.Split(dsn, \"?\")\n\tif len(args) != 2 {\n\t\treturn errors.New(\"query is mandatory (at least start_date and end_date or backlog)\")\n\t}\n\n\tfrags := strings.Split(args[0], \":\")\n\tif len(frags) != 2 {\n\t\treturn errors.New(\"cloudwatch path must contain group and stream : /my/group/name:stream/name\")\n\t}\n\n\ts.Config.GroupName = frags[0]\n\ts.Config.StreamName = &frags[1]\n\ts.Config.Labels = labels\n\ts.Config.UniqueId = uuid\n\n\tu, err := url.ParseQuery(args[1])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while parsing %s: %w\", dsn, err)\n\t}\n\n\tfor k, v := range u {\n\t\tswitch k {\n\t\tcase \"log_level\":\n\t\t\tif len(v) != 1 {\n\t\t\t\treturn errors.New(\"expected zero or one value for 'log_level'\")\n\t\t\t}","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/acquisition/modules/cloudwatch/config.go#L194-L230","documentation":"After the query split, the path portion must be exactly 'group:stream' — a single ':' separating the log group from the stream name. A path with zero or multiple ':' cannot identify both group and stream, so ConfigureByDSN returns this error.","triggerScenarios":"ConfigureByDSN receives a DSN whose path (before '?') splits on ':' into != 2 fragments, e.g. cloudwatch:///mygroup?backlog=1h (no stream) or cloudwatch:///a:b:c?backlog=1h (extra colon).","commonSituations":"Forgetting the ':stream' part of the DSN; using a stream name or group containing a literal ':'; typos when hand-editing DSN strings in acquisition.yaml.","solutions":["Format the DSN path as /<group-name>:<stream-name> with exactly one colon","URL-encode any ':' inside group/stream names instead of leaving it literal","Verify against the CloudWatch console that the group and stream names are correct"],"exampleFix":"// before\ncloudwatch:///my/log/group?backlog=1h\n// after\ncloudwatch:///my/log/group:my-stream?backlog=1h","handlingStrategy":"validation","validationCode":"path := strings.SplitN(strings.TrimPrefix(dsn, \"cloudwatch://\"), \"?\", 2)[0]\nif len(strings.Split(path, \":\")) != 2 { return errors.New(\"DSN path must be /group:stream\") }","typeGuard":"func cwPathOk(dsn string) bool {\n    p := strings.SplitN(strings.TrimPrefix(dsn, \"cloudwatch://\"), \"?\", 2)[0]\n    return len(strings.Split(p, \":\")) == 2\n}","tryCatchPattern":"if err := src.ConfigureByDSN(dsn, logger, labels, uuid); err != nil {\n    if strings.Contains(err.Error(), \"path must contain group and stream\") { /* fix /group:stream */ }\n    return err\n}","preventionTips":["Always format the DSN path as /<group>:<stream>","URL-encode colons inside group/stream names","Test the DSN with cscli or a dry run before deploying"],"tags":["cloudwatch","aws","dsn","url"],"backgroundTag":"invalid-url-format","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"}