crowdsecurity/crowdsec · error · QueryFail

query decision failed: %w

Error message

query decision failed: %w

What it means

Returned by Client.QueryDecisionWithFilter when its Scan of distinct decision fields (value/scope/origin) fails. Wraps QueryFail ("unable to query"); the real error is logged as 'QueryDecisionWithFilter : <err>'. Called by GetDecision (the LAPI GET /decisions handler).

Source

Thrown at pkg/database/decisions.go:152

	query, err = applyDecisionFilter(query, filter)
	if err != nil {
		return []*ent.Decision{}, err
	}

	err = query.Select(
		decision.FieldID,
		decision.FieldUntil,
		decision.FieldScenario,
		decision.FieldType,
		decision.FieldStartIP,
		decision.FieldEndIP,
		decision.FieldValue,
		decision.FieldScope,
		decision.FieldOrigin,
	).Scan(ctx, &data)
	if err != nil {
		c.Log.Warningf("QueryDecisionWithFilter : %s", err)
		return []*ent.Decision{}, fmt.Errorf("query decision failed: %w", QueryFail)
	}

	return data, nil
}

// ent translation of https://stackoverflow.com/a/28090544
func longestDecisionForScopeTypeValue(s *sql.Selector) {
	t := sql.Table(decision.Table)
	s.LeftJoin(t).OnP(sql.And(
		sql.ColumnsEQ(
			t.C(decision.FieldValue),
			s.C(decision.FieldValue),
		),
		sql.ColumnsEQ(
			t.C(decision.FieldType),
			s.C(decision.FieldType),
		),
		sql.ColumnsEQ(

View on GitHub (pinned to 909b515798)

Solutions

  1. Check LAPI logs for 'QueryDecisionWithFilter :' to see the driver error
  2. Verify DB reachability/locks; pause backups that take SQLite exclusive locks or use a server DB
  3. After a CrowdSec upgrade, ensure migrations completed (`cscli db migrate`)
  4. Have bouncers retry with backoff — this is a transient availability error, not a bad request

Example fix

// bouncer-side retry (pseudo)
// before
resp = lapi.GetDecisions()
// after
for i := 0; i < 3; i++ {
    resp, err = lapi.GetDecisions()
    if err == nil { break }
    time.Sleep(backoff(i))
}
Defensive patterns

Strategy: retry

Validate before calling

// client-side: confirm LAPI health before relying on decisions
resp, err := http.Get(lapiURL + "/health")
if err != nil || resp.StatusCode != 200 { return errors.New("LAPI unhealthy, skip decisions poll") }

Try / catch

decisions, err := client.GetDecision(ctx, filter)
if err != nil {
    // QueryFail sentinel: transient DB issue; back off and retry
    time.Sleep(2 * time.Second)
    decisions, err = client.GetDecision(ctx, filter)
}

Prevention

When it happens

Trigger: DB failure during the distinct-columns scan: connection error, SQLite lock, schema mismatch, or a filter applied via applyDecisionFilter already returned OK but the raw scan hits driver issues. Caller GetDecision propagates it to LAPI clients as an HTTP 500/403 response.

Common situations: Bouncer polls /decisions during a MySQL restart or SQLite backup lock; upgraded LAPI serving decisions to an old schema DB; disk I/O errors on the DB host.

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/71a25bd528a94b6e. Report an issue: GitHub.