crowdsecurity/crowdsec · error

groupby wrong type

Error message

groupby wrong type

What it means

After running the groupby expression, the result must be a string to use as the bucket partition key. If the expr returns a non-string (number, bool, array), PourItemToHolders logs a fatal and returns this error instead of building a key.

Source

Thrown at pkg/leakybucket/manager_run.go:255

			}
			if !condition {
				holders[idx].logger.Debugf("Event leaving node : ko (filter mismatch)")
				continue
			}
		}

		// groupby determines the partition key for the specific bucket
		var groupby string
		if holders[idx].RunTimeGroupBy != nil {
			tmpGroupBy, err := exprhelpers.Run(holders[idx].RunTimeGroupBy, map[string]any{"evt": &parsed}, holders[idx].logger, holders[idx].Spec.Debug)
			if err != nil {
				holders[idx].logger.Errorf("failed groupby : %v", err)
				return false, errors.New("leaky failed :/")
			}

			if groupby, ok = tmpGroupBy.(string); !ok {
				holders[idx].logger.Fatalf("failed groupby type : %v", err)
				return false, errors.New("groupby wrong type")
			}
		}
		buckey := holders[idx].BucketKey(groupby)

		// we need to either find the existing bucket, or create a new one (if it's the first event to hit it for this partition key)
		bucket, err := LoadOrStoreBucketFromHolder(ctx, buckey, buckets, &holders[idx], parsed.ExpectMode)
		if err != nil {
			return false, fmt.Errorf("failed to load or store bucket: %w", err)
		}
		// finally, pour the even into the bucket

		if bucket.Factory.orderEvent {
			if orderEvent == nil {
				orderEvent = make(map[string]*sync.WaitGroup)
			}
			if orderEvent[buckey] != nil {
				orderEvent[buckey].Wait()
			} else {

View on GitHub (pinned to 909b515798)

Solutions

  1. Cast the groupby expression to a string, e.g. `groupby: "string(evt.Parsed.status)"` or wrap with fmt
  2. Group on inherently string fields like evt.Meta.source_ip or evt.Parsed.username
  3. Restart crowdsec if it hit the Fatalf path, as the process may have exited

Example fix

# before
groupby: "evt.Parsed.status_code"
# after
groupby: "fmt.Sprintf("%v", evt.Parsed.status_code)"
Defensive patterns

Strategy: type-guard

Type guard

if s, ok := groupbyResult.(string); ok {
    key = s
} else {
    return fmt.Errorf("groupby must return string, got %T", groupbyResult)
}

Prevention

When it happens

Trigger: A scenario's `groupby:` expression evaluates successfully but returns a non-string value, e.g. `groupby: "evt.Parsed.status"` where status is an int.

Common situations: Groupby on numeric or boolean parsed fields, or on lists/maps, when the author intended a string identifier.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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