crowdsecurity/crowdsec · error · DeleteFail

alert graph delete batch decisions: %w

Error message

alert graph delete batch decisions: %w

What it means

DeleteAlertGraphBatch deletes decisions belonging to the alerts in the batch, then the alerts themselves. This error means the ent ORM bulk DELETE of decisions (via the alert owner edge) failed against the database, so the batch delete is aborted before any alert rows are removed. The message wraps the sentinel DeleteFail, so it signals a database-level delete failure rather than a caller mistake.

Source

Thrown at pkg/database/alerts.go:918

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

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

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

	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)

View on GitHub (pinned to 909b515798)

Solutions

  1. Check database connectivity and logs (the raw error is logged via c.Log.Warningf as 'DeleteAlertGraphBatch')
  2. Verify the DB user has DELETE privileges on the decisions table
  3. Retry the batch delete; partial state may need the single-alert DeleteAlertByID path
  4. If context timeouts are the cause, increase the request/context deadline

Example fix

// before
_, err := client.DeleteAlertGraphBatch(ctx, ids)
// after
if _, err := client.DeleteAlertGraphBatch(ctx, ids); err != nil {
    if errors.Is(err, entdb.DeleteFail) {
        log.Errorf("batch delete failed, check DB: %v", err)
        // check connectivity / retry
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// check DB reachability before batch delete
if err := client.Ent.Decision.Query().Limit(1).Exec(ctx); err != nil {
    return fmt.Errorf("database unavailable: %w", err)
}
if len(idList) == 0 { return nil }

Try / catch

deleted, err := client.DeleteAlertGraphBatch(ctx, ids)
if err != nil {
    if errors.Is(err, entdb.DeleteFail) {
        // database-level failure: check connectivity/grants, retry
    }
    return err
}

Prevention

When it happens

Trigger: c.DeleteAlertGraphBatch(ctx, idList) is called and the ent query Decision.Delete().Where(decision.HasOwnerWith(alert.IDIn(idList...))) fails: DB connection down/timeout, table locked, permission denied on the decisions table, or context cancelled mid-query.

Common situations: Database restarted or unreachable during alert cleanup; LAPI delete-batch API call (DELETE /alerts) hitting a DB with connection-pool exhaustion; migration drift leaving the decisions/alerts FK edges in an unexpected state.

Related errors


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