crowdsecurity/crowdsec · error · DeleteFail

event with alert ID '%d': %w

Error message

event with alert ID '%d': %w

What it means

DeleteAlertGraph removes all rows owned by one alert (events, meta, decisions, then the alert). This error means deleting the alert's Event rows failed, so the graph delete aborts with nothing else removed. The alert ID is embedded in the message and the cause is wrapped with the DeleteFail sentinel.

Source

Thrown at pkg/database/alerts.go:939

	deleted, err := c.Ent.Alert.Delete().
		Where(alert.IDIn(idList...)).Exec(ctx)
	if err != nil {
		c.Log.Warningf("DeleteAlertGraphBatch : %s", err)
		return deleted, fmt.Errorf("alert graph delete batch: %w", DeleteFail)
	}

	c.Log.Debug("Done batch delete alerts")

	return deleted, nil
}

func (c *Client) DeleteAlertGraph(ctx context.Context, alertItem *ent.Alert) error {
	// delete the associated events
	_, err := c.Ent.Event.Delete().
		Where(event.HasOwnerWith(alert.IDEQ(alertItem.ID))).Exec(ctx)
	if err != nil {
		c.Log.Warningf("DeleteAlertGraph : %s", err)
		return fmt.Errorf("event with alert ID '%d': %w", alertItem.ID, DeleteFail)
	}

	// delete the associated meta
	_, err = c.Ent.Meta.Delete().
		Where(meta.HasOwnerWith(alert.IDEQ(alertItem.ID))).Exec(ctx)
	if err != nil {
		c.Log.Warningf("DeleteAlertGraph : %s", err)
		return fmt.Errorf("meta with alert ID '%d': %w", alertItem.ID, DeleteFail)
	}

	// delete the associated decisions
	_, err = c.Ent.Decision.Delete().
		Where(decision.HasOwnerWith(alert.IDEQ(alertItem.ID))).Exec(ctx)
	if err != nil {
		c.Log.Warningf("DeleteAlertGraph : %s", err)
		return fmt.Errorf("decision with alert ID '%d': %w", alertItem.ID, DeleteFail)
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Read the underlying error logged as 'DeleteAlertGraph : %s'
  2. Verify connectivity and DELETE grants on the events table
  3. Retry the delete for the same alert ID
  4. Consider pruning events separately if the table is very large

Example fix

// before
err := client.DeleteAlertByID(ctx, alertID)
// after
if err := client.DeleteAlertByID(ctx, alertID); err != nil {
    if errors.Is(err, entdb.DeleteFail) {
        log.Errorf("failed deleting events for alert %d: %v", alertID, err)
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

exists, err := client.Ent.Alert.Query().Where(alert.IDEQ(id)).Exist(ctx)
if err != nil || !exists { return } // nothing to delete

Try / catch

err := client.DeleteAlertByID(ctx, id)
if err != nil && errors.Is(err, entdb.DeleteFail) {
    // events stage failed; verify DB health before retry
}

Prevention

When it happens

Trigger: DeleteAlertByID(ctx, id) -> DeleteAlertGraph: Event.Delete().Where(event.HasOwnerWith(alert.IDEQ(alertItem.ID))) fails due to DB unavailability, permission, lock, or cancelled context.

Common situations: cscli alerts delete on a machine whose DB connection has dropped; huge event tables causing long lock waits and timeouts; DB user without DELETE on events.

Related errors


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