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

  1. Inspect the wrapped inner error for the real cause (permissions, lock timeout, constraints).
  2. Retry the delete if it was a transient DB lock/timeout; batch large alert deletions into smaller ranges.
  3. Check API caller permissions if deletion came through LAPI (non-admin IPs are refused).
  4. 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

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


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/b20dae0ab78e5707. Report an issue: GitHub.