crowdsecurity/crowdsec · error · DeleteFail

alert with ID '%d': %w

Error message

alert with ID '%d': %w

What it means

The final step of DeleteAlertGraph: deleting the alert row itself after its children were removed. This error means Alert.DeleteOne(alertItem) failed — the alert persists even though its events/meta/decisions are gone. Wraps the DeleteFail sentinel.

Source

Thrown at pkg/database/alerts.go:962

		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)
	}

	// delete the alert
	err = c.Ent.Alert.DeleteOne(alertItem).Exec(ctx)
	if err != nil {
		c.Log.Warningf("DeleteAlertGraph : %s", err)
		return fmt.Errorf("alert with ID '%d': %w", alertItem.ID, DeleteFail)
	}

	return nil
}

func (c *Client) DeleteAlertByID(ctx context.Context, id int) error {
	alertItem, err := c.Ent.Alert.Query().Where(alert.IDEQ(id)).Only(ctx)
	if err != nil {
		return err
	}

	return c.DeleteAlertGraph(ctx, alertItem)
}

func (c *Client) DeleteAlertWithFilter(ctx context.Context, filter map[string][]string) (int, error) {
	preds, err := alertPredicatesFromFilter(filter)
	if err != nil {
		return 0, err

View on GitHub (pinned to 909b515798)

Solutions

  1. Read the 'DeleteAlertGraph : %s' warning for the underlying error
  2. If the alert no longer exists it was deleted concurrently — treat as success
  3. Retry DeleteAlertByID once; if it now returns not-found, cleanup is effectively complete
  4. Serialize concurrent deletes in your automation

Example fix

// before
err := client.DeleteAlertByID(ctx, id)
// after
err := client.DeleteAlertByID(ctx, id)
if err != nil && errors.Is(err, entdb.DeleteFail) {
    // maybe already deleted concurrently; verify before retrying
}
Defensive patterns

Strategy: try-catch

Validate before calling

exists, _ := client.Ent.Alert.Query().Where(alert.IDEQ(id)).Exist(ctx)
if !exists { return nil } // already deleted concurrently

Try / catch

err := client.DeleteAlertByID(ctx, id)
if err != nil {
    if _, checkErr := client.GetAlertByID(ctx, id); checkErr != nil {
        // alert gone: concurrent delete, treat as success
    }
}

Prevention

When it happens

Trigger: DeleteAlertByID(ctx, id) -> DeleteAlertGraph: Alert.DeleteOne(alertItem) fails, typically because the alert was concurrently deleted by another request, or a DB error (connection, grant, lock) occurs.

Common situations: Two LAPI requests deleting the same alert concurrently; DB failover; privileged-operational cleanup scripts racing with cscli alerts delete.

Related errors


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