{"record":{"id":"b20dae0ab78e5707","repo":"crowdsecurity/crowdsec","slug":"unable-to-delete","errorCode":null,"errorMessage":"unable to delete","messagePattern":"unable to delete","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/errors.go","lineNumber":12,"sourceCode":"package database\n\nimport \"errors\"\n\nvar (\n\tUserExists        = errors.New(\"user already exist\")\n\tUserNotExists     = errors.New(\"user doesn't exist\")\n\tHashError         = errors.New(\"unable to hash\")\n\tInsertFail        = errors.New(\"unable to insert row\")\n\tQueryFail         = errors.New(\"unable to query\")\n\tUpdateFail        = errors.New(\"unable to update\")\n\tDeleteFail        = errors.New(\"unable to delete\")\n\tItemNotFound      = errors.New(\"object not found\")\n\tParseTimeFail     = errors.New(\"unable to parse time\")\n\tParseDurationFail = errors.New(\"unable to parse duration\")\n\tMarshalFail       = errors.New(\"unable to serialize\")\n\tBulkError         = errors.New(\"unable to insert bulk\")\n\tParseType         = errors.New(\"unable to parse type\")\n\tInvalidIPOrRange  = errors.New(\"invalid ip address / range\")\n\tInvalidFilter     = errors.New(\"invalid filter\")\n)\n","sourceCodeStart":1,"sourceCodeEnd":22,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/errors.go#L1-L22","documentation":"DeleteFail is a sentinel error meaning a DELETE against the database failed. It is returned by alert-deletion paths (DeleteAlertGraph, DeleteAlertGraphBatch, TestDeleteAlertTrustedIPS) and decision expiry (ExpireDecisionsWithFilter), usually wrapped with the underlying ent/SQL error so errors.Is(err, database.DeleteFail) still matches.","triggerScenarios":"Deleting alerts via DELETE /v1/alerts when the DELETE query fails or is rejected; ExpireDecisionsWithFilter when the bulk decision deletion fails; DeleteAlertGraph/DeleteAlertGraphBatch when removing alert rows and children fails in a transaction.","commonSituations":"Deleting alerts from an unauthorized source IP (the API rejects with 403 mapped from delete failures in tests), database lock/timeout during large bulk deletes, FK constraint issues on very old schemas.","solutions":["Inspect the wrapped inner error for the real cause (permissions, lock timeout, constraints).","Retry the delete if it was a transient DB lock/timeout; batch large alert deletions into smaller ranges.","Check API caller permissions if deletion came through LAPI (non-admin IPs are refused).","Verify schema integrity/migrations for foreign-key layout."],"exampleFix":"// before\nerr := client.DeleteAlertGraph(ctx, alertIDs) // fails on huge batches\n// after\nfor chunk := range slices.Chunk(alertIDs, 100) {\n    if err := client.DeleteAlertGraph(ctx, chunk); err != nil {\n        return fmt.Errorf(\"deleting chunk: %w\", err)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Go: scope deletes to known, existing IDs in small batches\nids, err := client.ListAlertIdsByFilter(ctx, sinceFilter)\nif err != nil { return err }","typeGuard":"func isDeleteFail(err error) bool { return errors.Is(err, database.DeleteFail) }","tryCatchPattern":"if err := client.DeleteAlertGraph(ctx, ids); err != nil {\n    if errors.Is(err, database.DeleteFail) {\n        log.Warnf(\"delete failed, retrying smaller batch: %v\", err)\n        return retryChunked(ids)\n    }\n    return err\n}","preventionTips":["Chunk large deletions instead of one huge DELETE","Ensure API callers have permission to delete (admin IP) ","Watch for DB lock timeouts during bulk maintenance"],"tags":["database","crowdsec","delete"],"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"}