crowdsecurity/crowdsec · error · DeleteFail

expire decisions with provided filter: %w

Error message

expire decisions with provided filter: %w

What it means

After building the query, ExpireDecisionsWithFilter fetches the matching decisions with decisions.All(ctx). If the database query fails (connection issue, schema problem, context cancellation), it logs a warning and wraps the failure in the DeleteFail sentinel with this message, aborting the expiry operation.

Source

Thrown at pkg/database/decisions.go:268

			if err != nil {
				return 0, nil, fmt.Errorf("unable to convert '%s' to int: %w: %w", value[0], err, InvalidIPOrRange)
			}
		case "scenario":
			decisions = decisions.Where(decision.ScenarioEQ(value[0]))
		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
}

View on GitHub (pinned to 909b515798)

Solutions

  1. Check database connectivity and that ent migrations ran (cscli db migrate / restart with a healthy DB)
  2. Narrow the filter so the query returns fewer rows and completes before context timeout
  3. Inspect the logged warning 'ExpireDecisionsWithFilter' for the underlying DB error
  4. Check errors.Is(err, database.DeleteFail) in callers to map to a 500

Example fix

// before
res, err := client.ExpireDecisionsWithFilter(ctx, filter) // ctx without deadline
// after
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
res, err := client.ExpireDecisionsWithFilter(ctx, filter)
Defensive patterns

Strategy: retry

Validate before calling

if err := entClient.Decision.Query().Limit(1).FirstErr(ctx); err != nil {
    return fmt.Errorf("database unavailable: %w", err)
}

Try / catch

count, _, err := client.ExpireDecisionsWithFilter(ctx, filter)
if err != nil {
    if errors.Is(err, database.DeleteFail) && netErrTransient(err) {
        time.Sleep(backoff); return client.ExpireDecisionsWithFilter(ctx, filter)
    }
    return err
}

Prevention

When it happens

Trigger: decisions.All(ctx) returning a DB error: database unreachable, ent schema mismatch, context deadline exceeded during a large filtered query.

Common situations: SQLite file locked or corrupted; LAPI losing the DB connection mid-request; very broad filters scanning millions of rows and timing out; migrations not applied after an upgrade.

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/74bc2afb68dfe006. Report an issue: GitHub.