crowdsecurity/crowdsec · error

could not delete alerts: %w

Error message

could not delete alerts: %w

What it means

The ent DELETE removing alerts below the computed max ID (total count minus maxItems) failed in FlushAlerts' max-items branch. The query keeps alerts with active decisions; the failure is at DB execution. Orphan alerts may remain on MySQL — a later flush run cleans them up, which is expected, not data loss.

Source

Thrown at pkg/database/flush.go:385

			return fmt.Errorf("could not get last alert: %w", err)
		}

		if len(lastAlert) != 0 {
			maxid := lastAlert[0].ID - maxItems

			c.Log.Debugf("FlushAlerts (max id): %d", maxid)

			if maxid > 0 {
				// This may lead to orphan alerts (at least on MySQL), but the next time the flush job will run, they will be deleted
				// Alerts that still carry an active decision are kept regardless of the count: deleting them would
				// cascade-delete the live decision. They are flushed on a later run, once their decisions expire.
				deletedByNbItem, err = c.Ent.Alert.Delete().Where(
					alert.IDLT(maxid),
					alertWithoutActiveDecision(time.Now().UTC()),
				).Exec(ctx)
				if err != nil {
					c.Log.Errorf("FlushAlerts: Could not delete alerts: %s", err)
					return fmt.Errorf("could not delete alerts: %w", err)
				}
			}
		}
	}

	if deletedByNbItem > 0 {
		c.Log.Infof("flushed %d/%d alerts because the max number of alerts has been reached (%d max)",
			deletedByNbItem, totalAlerts, maxItems)
	}

	if deletedByAge > 0 {
		c.Log.Infof("flushed %d/%d alerts because they were created %s ago or more",
			deletedByAge, totalAlerts, maxAge)
	}

	return nil
}

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped driver error in logs for the exact SQL failure
  2. Restore database connectivity/locks and let the next flush cycle retry
  3. If context cancellation, avoid stopping crowdsec during heavy flushes or increase flush frequency so batches stay small
  4. Check disk space on the DB volume — full disk fails deletes
Defensive patterns

Strategy: try-catch

Validate before calling

// check disk space / connectivity before large flush
if err := db.Ping(); err != nil { skipFlush = true }

Try / catch

if err := c.FlushAlerts(ctx, since, maxItems); err != nil {
    if errors.Is(err, context.Canceled) { return } // shutdown, not a fault
    scheduleRetry(nextFlushInterval)
}

Prevention

When it happens

Trigger: The `Alert.Delete().Where(alert.IDLT(maxid), alertWithoutActiveDecision(...))` ent mutation fails — DB connection loss, driver-level constraint, or ctx cancellation during the delete.

Common situations: Database restarted mid-flush; SQLite lock contention with a concurrently running LAPI write; connection pool exhausted on MySQL/Postgres.

Related errors


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