crowdsecurity/crowdsec · error · QueryFail

get expired decisions with filters: %w

Error message

get expired decisions with filters: %w

What it means

Returned by QueryExpiredDecisionsWithFilters when applyDecisionFilter cannot build predicates from the filter map. Wraps QueryFail ("unable to query"); the actual parse error is logged as 'QueryExpiredDecisionsWithFilters : <err>'.

Source

Thrown at pkg/database/decisions.go:89

	return latest.ID, nil
}

func (c *Client) QueryExpiredDecisionsWithFilters(ctx context.Context, now time.Time, filter map[string][]string) ([]*ent.Decision, error) {
	query := c.Ent.Decision.Query().
		Select(decision.FieldID, decision.FieldUntil, decision.FieldScenario, decision.FieldScope, decision.FieldValue, decision.FieldType, decision.FieldOrigin, decision.FieldUUID).
		Where(
			decision.UntilLT(now),
		)
	// Allow a bouncer to ask for non-deduplicated results
	if v, ok := filter["dedup"]; !ok || v[0] != "false" {
		query = query.Where(longestDecisionForScopeTypeValue)
	}

	query, err := applyDecisionFilter(query, filter)
	if err != nil {
		c.Log.Warningf("QueryExpiredDecisionsWithFilters : %s", err)
		return []*ent.Decision{}, fmt.Errorf("get expired decisions with filters: %w", QueryFail)
	}

	query = query.Order(ent.Asc(decision.FieldID))

	data, err := query.All(ctx)
	if err != nil {
		c.Log.Warningf("QueryExpiredDecisionsWithFilters : %s", err)
		return []*ent.Decision{}, fmt.Errorf("expired decisions: %w", QueryFail)
	}

	return data, nil
}

func (c *Client) QueryDecisionCountByScenario(ctx context.Context) ([]*DecisionsByScenario, error) {
	query := c.Ent.Decision.Query().Where(
		decision.UntilGT(time.Now().UTC()),
	)

View on GitHub (pinned to 909b515798)

Solutions

  1. Read the 'QueryExpiredDecisionsWithFilters :' warning in the logs for the concrete parse error
  2. Fix the offending filter key/value (valid keys: scope, value, type, origin, scenario, ip/since, etc.)
  3. If a bouncer produces it, check bouncer version compatibility with your CrowdSec LAPI version
  4. Test the same filter with `cscli decisions list --origin ... --scope ...` to isolate it

Example fix

// before
cscli bouncers list  # bouncer sends since=abc
// after — pass a valid duration
cscli decisions delete --expired-since 1h
Defensive patterns

Strategy: validation

Validate before calling

if d, err := time.ParseDuration(sinceVal); err != nil || d <= 0 {
    return fmt.Errorf("invalid 'since' filter %q", sinceVal)
}
if scope == "ip" {
    if net.ParseIP(value) == nil {
        if _, _, err := net.ParseCIDR(value); err != nil {
            return fmt.Errorf("invalid ip/cidr filter value %q", value)
        }
    }
}

Try / catch

res, err := client.QueryExpiredDecisionsWithFilters(ctx, now, filter)
if err != nil && strings.Contains(err.Error(), "unable to query") {
    log.Warnf("filter rejected: %v — check 'QueryExpiredDecisionsWithFilters' in LAPI logs", err)
    return fallbackUnfiltered(ctx)
}

Prevention

When it happens

Trigger: Caller passes malformed filter entries (bad 'since' duration value, invalid scope/type/value combination, unparsable IP in contains-ip) while querying decisions that expired at time `now`.

Common situations: cscli or a bouncer passes an invalid duration like 'since=1x' or a scope value with wrong case/format; custom bouncer builds filters with keys this LAPI version doesn't recognize.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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