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, errView on GitHub (pinned to 909b515798)
Solutions
- Read the 'DeleteAlertGraph : %s' warning for the underlying error
- If the alert no longer exists it was deleted concurrently — treat as success
- Retry DeleteAlertByID once; if it now returns not-found, cleanup is effectively complete
- 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
- Serialize delete operations for the same alert
- Treat 'not found after failure' as success in cleanup scripts
- Check DB grants on alerts
- Log and dedupe concurrent delete attempts in automation
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
- alert graph delete batch events: %w
- alert graph delete batch meta: %w
- unable to delete
- event meta '%v': %w: %w
- machine '%s': %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/205525df0272f669.
Report an issue: GitHub.