{"record":{"id":"5acc93983b1b2456","repo":"crowdsecurity/crowdsec","slug":"invalid-contains-value-w-w-5acc93","errorCode":null,"errorMessage":"invalid contains value: %w: %w","messagePattern":"invalid contains value: %w: %w","errorType":"validation","errorClass":"InvalidFilter","httpStatus":null,"severity":"warning","filePath":"pkg/database/decisionfilter.go","lineNumber":41,"sourceCode":"\t  else, return bans that are *contained* by the given value (value is the outer)*/\n\n\t/*the simulated filter is a bit different : if it's not present *or* set to false, specifically exclude records with simulated to true */\n\tif v, ok := filter[\"simulated\"]; ok {\n\t\tif v[0] == \"false\" {\n\t\t\tquery = query.Where(decision.SimulatedEQ(false))\n\t\t}\n\n\t\tdelete(filter, \"simulated\")\n\t} else {\n\t\tquery = query.Where(decision.SimulatedEQ(false))\n\t}\n\n\tfor param, value := range filter {\n\t\tswitch param {\n\t\tcase \"contains\":\n\t\t\tcontains, err = strconv.ParseBool(value[0])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid contains value: %w: %w\", err, InvalidFilter)\n\t\t\t}\n\t\tcase \"scopes\", \"scope\": // Swagger mentions both of them, let's just support both to make sure we don't break anything\n\t\t\tscopes := strings.Split(value[0], \",\")\n\t\t\tfor i, scope := range scopes {\n\t\t\t\tswitch strings.ToLower(scope) {\n\t\t\t\tcase \"ip\":\n\t\t\t\t\tscopes[i] = types.Ip\n\t\t\t\tcase \"range\":\n\t\t\t\t\tscopes[i] = types.Range\n\t\t\t\tcase \"country\":\n\t\t\t\t\tscopes[i] = types.Country\n\t\t\t\tcase \"as\":\n\t\t\t\t\tscopes[i] = types.AS\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tquery = query.Where(decision.ScopeIn(scopes...))\n\t\tcase \"value\":","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/decisionfilter.go#L23-L59","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Send only strconv.ParseBool-accepted values: true/false (or 1/0, t/f, TRUE/FALSE variants).","Remove the 'contains' parameter entirely if you don't need it (defaults to false semantics).","In client code, parse and validate the boolean before building the request.","Check the wrapped strconv error to confirm it is a syntax error, not something else."],"exampleFix":"// before\nGET /v1/decisions?contains=yes\n// after\nGET /v1/decisions?contains=true","handlingStrategy":"validation","validationCode":"func validContains(v string) bool {\n    _, err := strconv.ParseBool(v)\n    return err == nil\n}\n// use: validContains(containsParam) || omit param","typeGuard":null,"tryCatchPattern":"resp, err := lapi.GetDecisions(ctx, models.GetDecisionsOpts{Contains: &contains})\nif err != nil && strings.Contains(err.Error(), \"invalid contains value\") {\n    return fmt.Errorf(\"client bug: contains must be a bool, got %q\", containsRaw)\n}","preventionTips":["Only send true/false for boolean query params","Never interpolate raw user input into query strings","Serialize bools with a typed API client, not string concat","Add client-side unit tests for filter serialization"],"tags":["api","query-parameter","validation"],"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-14T05:17:10.506Z"}