{"record":{"id":"4b03ee63ffc93895","repo":"crowdsecurity/crowdsec","slug":"alert-graph-delete-batch-w","errorCode":null,"errorMessage":"alert graph delete batch: %w","messagePattern":"alert graph delete batch: %w","errorType":"exception","errorClass":"DeleteFail","httpStatus":null,"severity":"error","filePath":"pkg/database/alerts.go","lineNumber":925,"sourceCode":"\t_, err = c.Ent.Meta.Delete().\n\t\tWhere(meta.HasOwnerWith(alert.IDIn(idList...))).Exec(ctx)\n\tif err != nil {\n\t\tc.Log.Warningf(\"DeleteAlertGraphBatch : %s\", err)\n\t\treturn 0, fmt.Errorf(\"alert graph delete batch meta: %w\", DeleteFail)\n\t}\n\n\t_, err = c.Ent.Decision.Delete().\n\t\tWhere(decision.HasOwnerWith(alert.IDIn(idList...))).Exec(ctx)\n\tif err != nil {\n\t\tc.Log.Warningf(\"DeleteAlertGraphBatch : %s\", err)\n\t\treturn 0, fmt.Errorf(\"alert graph delete batch decisions: %w\", DeleteFail)\n\t}\n\n\tdeleted, err := c.Ent.Alert.Delete().\n\t\tWhere(alert.IDIn(idList...)).Exec(ctx)\n\tif err != nil {\n\t\tc.Log.Warningf(\"DeleteAlertGraphBatch : %s\", err)\n\t\treturn deleted, fmt.Errorf(\"alert graph delete batch: %w\", DeleteFail)\n\t}\n\n\tc.Log.Debug(\"Done batch delete alerts\")\n\n\treturn deleted, nil\n}\n\nfunc (c *Client) DeleteAlertGraph(ctx context.Context, alertItem *ent.Alert) error {\n\t// delete the associated events\n\t_, err := c.Ent.Event.Delete().\n\t\tWhere(event.HasOwnerWith(alert.IDEQ(alertItem.ID))).Exec(ctx)\n\tif err != nil {\n\t\tc.Log.Warningf(\"DeleteAlertGraph : %s\", err)\n\t\treturn fmt.Errorf(\"event with alert ID '%d': %w\", alertItem.ID, DeleteFail)\n\t}\n\n\t// delete the associated meta\n\t_, err = c.Ent.Meta.Delete().","sourceCodeStart":907,"sourceCodeEnd":943,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/alerts.go#L907-L943","documentation":"In DeleteAlertGraphBatch, after the associated decisions are removed, the alerts themselves are bulk-deleted. This error means that final Alert.Delete() call failed, so the alerts (and possibly already-deleted decisions) are in a partially cleaned state. It wraps the DeleteFail sentinel indicating a database delete failure.","triggerScenarios":"c.DeleteAlertGraphBatch(ctx, idList) is called, decision deletion succeeded, but Alert.Delete().Where(alert.IDIn(idList...)) fails: connection loss between the two statements, lock contention on alerts, insufficient DELETE grants, or context cancellation.","commonSituations":"Large batch deletes timing out under lock contention while a machine still streams alerts; DB failover mid-request on LAPI; low-privileged DB user missing DELETE on alerts.","solutions":["Inspect the warning log 'DeleteAlertGraphBatch : %s' for the underlying DB error","Retry the batch delete — decisions were already removed, remaining alerts should delete cleanly","Check DB grants and connection stability","Reduce batch size to avoid long-running transactions/locks"],"exampleFix":"// before\ndeleted, err := client.DeleteAlertGraphBatch(ctx, ids)\n// after\ndeleted, err := client.DeleteAlertGraphBatch(ctx, ids)\nif err != nil && errors.Is(err, entdb.DeleteFail) {\n    log.Warnf(\"partial delete: %d alerts affected, retry\", deleted)\n}","handlingStrategy":"retry","validationCode":"if err := client.Ent.Alert.Query().Where(alert.IDIn(ids...)).Exist(ctx); err != nil {\n    return fmt.Errorf(\"cannot reach alerts table: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"deleted, err := client.DeleteAlertGraphBatch(ctx, ids)\nif errors.Is(err, entdb.DeleteFail) {\n    // decisions may already be gone; safe to retry the batch\n    deleted, err = client.DeleteAlertGraphBatch(ctx, ids)\n}","preventionTips":["Treat batch deletes as retryable — the query filters by ID, so retries are idempotent","Avoid running huge batches during peak DB load","Ensure the alerts table has no FK rows blocking deletion","Watch for lock contention with concurrent LAPI requests"],"tags":["database","delete","ent"],"backgroundTag":"database-write-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}