crowdsecurity/crowdsec · error
unable to delete
Error message
unable to delete
What it means
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.
Source
Thrown at pkg/database/errors.go:12
package database
import "errors"
var (
UserExists = errors.New("user already exist")
UserNotExists = errors.New("user doesn't exist")
HashError = errors.New("unable to hash")
InsertFail = errors.New("unable to insert row")
QueryFail = errors.New("unable to query")
UpdateFail = errors.New("unable to update")
DeleteFail = errors.New("unable to delete")
ItemNotFound = errors.New("object not found")
ParseTimeFail = errors.New("unable to parse time")
ParseDurationFail = errors.New("unable to parse duration")
MarshalFail = errors.New("unable to serialize")
BulkError = errors.New("unable to insert bulk")
ParseType = errors.New("unable to parse type")
InvalidIPOrRange = errors.New("invalid ip address / range")
InvalidFilter = errors.New("invalid filter")
)
View on GitHub (pinned to 909b515798)
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.
Example fix
// before
err := client.DeleteAlertGraph(ctx, alertIDs) // fails on huge batches
// after
for chunk := range slices.Chunk(alertIDs, 100) {
if err := client.DeleteAlertGraph(ctx, chunk); err != nil {
return fmt.Errorf("deleting chunk: %w", err)
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: scope deletes to known, existing IDs in small batches
ids, err := client.ListAlertIdsByFilter(ctx, sinceFilter)
if err != nil { return err } Type guard
func isDeleteFail(err error) bool { return errors.Is(err, database.DeleteFail) } Try / catch
if err := client.DeleteAlertGraph(ctx, ids); err != nil {
if errors.Is(err, database.DeleteFail) {
log.Warnf("delete failed, retrying smaller batch: %v", err)
return retryChunked(ids)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- no database configuration provided
- unable to update
- object not found
- unable to parse time
- unable to parse duration
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/b20dae0ab78e5707.
Report an issue: GitHub.