crowdsecurity/crowdsec · error

cloudwatch path must contain group and stream : /my/group/na

Error message

cloudwatch path must contain group and stream : /my/group/name:stream/name

What it means

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.

Source

Thrown at pkg/acquisition/modules/cloudwatch/config.go:212

	s.logger.Infof("Adding cloudwatch group '%s' (stream:%s) to datasources", s.Config.GroupName, targetStream)

	return nil
}

func (s *Source) ConfigureByDSN(ctx context.Context, dsn string, labels map[string]string, logger *log.Entry, uuid string) error {
	s.logger = logger

	dsn = strings.TrimPrefix(dsn, s.GetName()+"://")

	args := strings.Split(dsn, "?")
	if len(args) != 2 {
		return errors.New("query is mandatory (at least start_date and end_date or backlog)")
	}

	frags := strings.Split(args[0], ":")
	if len(frags) != 2 {
		return errors.New("cloudwatch path must contain group and stream : /my/group/name:stream/name")
	}

	s.Config.GroupName = frags[0]
	s.Config.StreamName = &frags[1]
	s.Config.Labels = labels
	s.Config.UniqueId = uuid

	u, err := url.ParseQuery(args[1])
	if err != nil {
		return fmt.Errorf("while parsing %s: %w", dsn, err)
	}

	for k, v := range u {
		switch k {
		case "log_level":
			if len(v) != 1 {
				return errors.New("expected zero or one value for 'log_level'")
			}

View on GitHub (pinned to 909b515798)

Solutions

  1. Format the DSN path as /<group-name>:<stream-name> with exactly one colon
  2. URL-encode any ':' inside group/stream names instead of leaving it literal
  3. Verify against the CloudWatch console that the group and stream names are correct

Example fix

// before
cloudwatch:///my/log/group?backlog=1h
// after
cloudwatch:///my/log/group:my-stream?backlog=1h
Defensive patterns

Strategy: validation

Validate before calling

path := strings.SplitN(strings.TrimPrefix(dsn, "cloudwatch://"), "?", 2)[0]
if len(strings.Split(path, ":")) != 2 { return errors.New("DSN path must be /group:stream") }

Type guard

func cwPathOk(dsn string) bool {
    p := strings.SplitN(strings.TrimPrefix(dsn, "cloudwatch://"), "?", 2)[0]
    return len(strings.Split(p, ":")) == 2
}

Try / catch

if err := src.ConfigureByDSN(dsn, logger, labels, uuid); err != nil {
    if strings.Contains(err.Error(), "path must contain group and stream") { /* fix /group:stream */ }
    return err
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/5fa0b2de35f53c24. Report an issue: GitHub.