{"record":{"id":"239ca63d30848841","repo":"crowdsecurity/crowdsec","slug":"alert-graph-delete-batch-meta-w","errorCode":null,"errorMessage":"alert graph delete batch meta: %w","messagePattern":"alert graph delete batch meta: %w","errorType":"exception","errorClass":"DeleteFail","httpStatus":null,"severity":"error","filePath":"pkg/database/alerts.go","lineNumber":911,"sourceCode":"\nfunc (c *Client) DeleteAlertGraphBatch(ctx context.Context, alertItems []*ent.Alert) (int, error) {\n\tidList := make([]int, 0)\n\tfor _, alert := range alertItems {\n\t\tidList = append(idList, alert.ID)\n\t}\n\n\t_, err := c.Ent.Event.Delete().\n\t\tWhere(event.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 events: %w\", DeleteFail)\n\t}\n\n\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","sourceCodeStart":893,"sourceCodeEnd":929,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/alerts.go#L893-L929","documentation":"DeleteAlertGraphBatch deletes meta rows owned by the alerts in idList; on failure it logs the raw error and returns DeleteFail wrapped. Events deletion had succeeded (or was skipped) but the meta cleanup failed, potentially leaving orphaned meta rows.","triggerScenarios":"c.Ent.Meta.Delete().Where(meta.HasOwnerWith(alert.IDIn(...))).Exec(ctx) fails — DB connectivity, lock contention, oversized ID list, context cancelled.","commonSituations":"Large batch alert deletion against SQLite under lock contention; connection dropped between the event and meta delete statements; MySQL deadlock with a concurrent alert writer.","solutions":["Check the preceding Warningf log for the raw driver error","Retry DeleteAlertGraphBatch; deletion is per-graph step so re-running is safe for cleanup","Reduce batch size if IN-clause limits are implicated","Inspect for orphaned meta rows if the failure persists and clean with a manual delete by alert_id"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if len(idList) == 0 {\n    return nil\n}","typeGuard":null,"tryCatchPattern":"_, err := client.DeleteAlertGraphBatch(ctx, ids)\nif err != nil {\n    // safe to retry; verify meta cleanup afterwards\n    return retryAfterCleanup(ctx, ids)\n}","preventionTips":["Keep batch sizes within driver IN-clause limits","Serialize large deletions against concurrent alert writes","Periodically check for orphaned meta/decision rows after failed deletes"],"tags":["database","delete","alerts"],"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-14T00:17:10.932Z"}