crowdsecurity/crowdsec · error
multiple alerts found for uuid %s
Error message
multiple alerts found for uuid %s
What it means
CreateOrUpdateAlert looks up alerts by UUID, which is expected to be unique. If more than one alert row matches the same UUID, it returns 'multiple alerts found for uuid %s' instead of guessing which one to update (commented 'this should never happen'). It signals a uniqueness violation in the alerts table.
Source
Thrown at pkg/database/alerts.go:72
// alert wasn't found, insert it (expected hotpath)
if ent.IsNotFound(err) || len(alerts) == 0 {
alertIDs, err := c.CreateAlert(ctx, machineID, []*models.Alert{alertItem})
if err != nil {
return "", fmt.Errorf("unable to create alert: %w", err)
}
// happy nilaway
if len(alertIDs) == 0 {
return "", fmt.Errorf("unable to create alert: no IDs returned for alert %s", alertItem.UUID)
}
return alertIDs[0], nil
}
// this should never happen
if len(alerts) > 1 {
return "", fmt.Errorf("multiple alerts found for uuid %s", alertItem.UUID)
}
log.Infof("Alert %s already exists, checking associated decisions", alertItem.UUID)
// alert is found, check for any missing decisions
newUuids := make([]string, len(alertItem.Decisions))
for i, decItem := range alertItem.Decisions {
newUuids[i] = decItem.UUID
}
foundAlert := alerts[0]
foundUuids := make([]string, len(foundAlert.Edges.Decisions))
for i, decItem := range foundAlert.Edges.Decisions {
foundUuids[i] = decItem.UUID
}
View on GitHub (pinned to 909b515798)
Solutions
- Inspect duplicates: SELECT id, uuid FROM alerts WHERE uuid = '<uuid>'; on the crowdsec DB
- Delete the extra duplicate rows keeping one (backup the DB first: cp crowdsec.db crowdsec.db.bak)
- If duplicates are widespread, consider dumping alerts ('cscli alerts export' if available) and pruning with 'cscli alerts delete --all' to rebuild cleanly
- Upgrade crowdsec to a version enforcing alert UUID uniqueness
Example fix
// sqlite cleanup (backup first!) // before: two rows share the uuid // after: keep the oldest row DELETE FROM alerts WHERE uuid = 'xxxxxxxx-...' AND id NOT IN ( SELECT MIN(id) FROM alerts WHERE uuid = 'xxxxxxxx-...' );
Defensive patterns
Strategy: validation
Validate before calling
// detect duplicate UUIDs in the DB before pushing updates
rows, err := db.Query("SELECT COUNT(*) FROM alerts WHERE uuid = ?", alertUUID)
if err == nil && rows.Next() {
var n int; rows.Scan(&n)
if n > 1 { return errors.New("duplicate alert UUIDs in database; deduplicate first") }
} Try / catch
id, err := client.CreateOrUpdateAlert(ctx, machineID, alert)
if err != nil && strings.HasPrefix(err.Error(), "multiple alerts found for uuid") {
// stop retrying — requires DB-level dedup, not a retry
return ErrCorruptAlertTable
} Prevention
- Never hand-edit or bulk-import into the crowdsec SQLite DB without constraint checks
- Back up crowdsec.db before manual maintenance
- Upgrade from very old crowdsec versions through the documented migration path
- Alert on duplicate-UUID errors early — they indicate DB corruption risks
When it happens
Trigger: The SELECT alert.UUID(alertItem.UUID) returns len(alerts) > 1 — i.e., duplicate rows with the same UUID exist in the database, typically from a historical bug, manual DB manipulation, or an import that bypassed the unique constraint.
Common situations: Databases populated by old crowdsec versions before strict uniqueness, bulk imports from CAPI sync gone wrong, or hand-edited SQLite files. Rare in practice.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- no database configuration provided
- unable to update
- unable to delete
- object not found
- unable to parse time
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/6d7f15df889bf69a.
Report an issue: GitHub.