crowdsecurity/crowdsec · error · DeleteFail
expire decisions with provided filter: %w: %w
Error message
expire decisions with provided filter: %w: %w
What it means
After the candidate decisions are fetched, ExpireDecisionsWithFilter calls ExpireDecisions to set their until_ts to now. If that bulk update fails, the underlying error is wrapped with the DeleteFail sentinel and this message, meaning the filter matched rows but the expiry write itself failed.
Source
Thrown at pkg/database/decisions.go:273
default:
return 0, nil, fmt.Errorf("'%s' doesn't exist: %w", param, InvalidFilter)
}
}
decisions, err = decisionIPFilter(decisions, contains, rng)
if err != nil {
return 0, nil, err
}
decisionsToDelete, err := decisions.All(ctx)
if err != nil {
c.Log.Warningf("ExpireDecisionsWithFilter : %s", err)
return 0, nil, fmt.Errorf("expire decisions with provided filter: %w", DeleteFail)
}
count, err := c.ExpireDecisions(ctx, decisionsToDelete)
if err != nil {
return 0, nil, fmt.Errorf("expire decisions with provided filter: %w: %w", err, DeleteFail)
}
return count, decisionsToDelete, err
}
func decisionIDs(decisions []*ent.Decision) []int {
ids := make([]int, len(decisions))
for i, d := range decisions {
ids[i] = d.ID
}
return ids
}
// expireDecisionBatch expires the decisions as a single operation.
func (c *Client) expireDecisionBatch(ctx context.Context, batch []*ent.Decision, now time.Time) (int, error) {
ids := decisionIDs(batch)
View on GitHub (pinned to 909b515798)
Solutions
- Retry the operation; the failure is at the write stage and the filter query already succeeded
- Check DB connectivity and lock contention (show processlist / SQLite busy_timeout)
- Verify disk space and DB write permissions for the crowdsec process
- Check errors.Is(err, database.DeleteFail) to map to a 500 in API handlers
Example fix
// before
count, _, err := client.ExpireDecisionsWithFilter(ctx, filter)
if err != nil { return err }
// after
count, _, err := client.ExpireDecisionsWithFilter(ctx, filter)
if errors.Is(err, database.DeleteFail) {
return fmt.Errorf("decision expiry failed, check database: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// ensure DB is reachable and writable before the bulk update
if err := entClient.Ping(ctx); err != nil { return err } Try / catch
if _, _, err := client.ExpireDecisionsWithFilter(ctx, filter); err != nil {
if errors.Is(err, database.DeleteFail) {
// retry once after short backoff; check inner error for lock/conn issues
}
return err
} Prevention
- Avoid many concurrent writers doing bulk expiry on the same table
- For SQLite, set busy_timeout to tolerate lock contention
- Ensure adequate disk space on the DB volume
When it happens
Trigger: ExpireDecisions returning an error: DB connection dropped between query and update, write lock contention on decision table, context cancelled mid-update.
Common situations: Concurrent LAPI writers contending on the decisions table; SQLite 'database is locked' under parallel cscli commands; DB going away during long maintenance jobs.
Related errors
- expire decisions with provided filter: %w
- hard delete decisions with provided filter: %w
- while getting allowlist %s: %s
- while getting alert: %w
- while getting decision: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/d217b52cb69e0788.
Report an issue: GitHub.