crowdsecurity/crowdsec · warning · InvalidFilter

invalid contains value: %w: %w

Error message

invalid contains value: %w: %w

What it means

applyDecisionFilter rejects the request because the 'contains' query parameter is not a valid boolean. The filter builder wraps strconv.ParseBool's error together with the sentinel InvalidFilter so API callers can identify it as a client-supplied bad filter.

Source

Thrown at pkg/database/decisionfilter.go:41

	  else, return bans that are *contained* by the given value (value is the outer)*/

	/*the simulated filter is a bit different : if it's not present *or* set to false, specifically exclude records with simulated to true */
	if v, ok := filter["simulated"]; ok {
		if v[0] == "false" {
			query = query.Where(decision.SimulatedEQ(false))
		}

		delete(filter, "simulated")
	} else {
		query = query.Where(decision.SimulatedEQ(false))
	}

	for param, value := range filter {
		switch param {
		case "contains":
			contains, err = strconv.ParseBool(value[0])
			if err != nil {
				return nil, fmt.Errorf("invalid contains value: %w: %w", err, InvalidFilter)
			}
		case "scopes", "scope": // Swagger mentions both of them, let's just support both to make sure we don't break anything
			scopes := strings.Split(value[0], ",")
			for i, scope := range scopes {
				switch strings.ToLower(scope) {
				case "ip":
					scopes[i] = types.Ip
				case "range":
					scopes[i] = types.Range
				case "country":
					scopes[i] = types.Country
				case "as":
					scopes[i] = types.AS
				}
			}

			query = query.Where(decision.ScopeIn(scopes...))
		case "value":

View on GitHub (pinned to 909b515798)

Solutions

  1. Send only strconv.ParseBool-accepted values: true/false (or 1/0, t/f, TRUE/FALSE variants).
  2. Remove the 'contains' parameter entirely if you don't need it (defaults to false semantics).
  3. In client code, parse and validate the boolean before building the request.
  4. Check the wrapped strconv error to confirm it is a syntax error, not something else.

Example fix

// before
GET /v1/decisions?contains=yes
// after
GET /v1/decisions?contains=true
Defensive patterns

Strategy: validation

Validate before calling

func validContains(v string) bool {
    _, err := strconv.ParseBool(v)
    return err == nil
}
// use: validContains(containsParam) || omit param

Try / catch

resp, err := lapi.GetDecisions(ctx, models.GetDecisionsOpts{Contains: &contains})
if err != nil && strings.Contains(err.Error(), "invalid contains value") {
    return fmt.Errorf("client bug: contains must be a bool, got %q", containsRaw)
}

Prevention

When it happens

Trigger: Hitting the Local API decisions endpoints (e.g. GET /v1/decisions?contains=yes123) with a 'contains' value outside strconv.ParseBool's accepted set (1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False).

Common situations: Scripts passing 'yes'/'no', 'on'/'off', or an empty value for contains; bouncers written against an assumed API contract; URL-encoded or duplicated parameters garbling the boolean.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


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