{"record":{"id":"6d7f15df889bf69a","repo":"crowdsecurity/crowdsec","slug":"multiple-alerts-found-for-uuid-s","errorCode":null,"errorMessage":"multiple alerts found for uuid %s","messagePattern":"multiple alerts found for uuid (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/alerts.go","lineNumber":72,"sourceCode":"\n\t// alert wasn't found, insert it (expected hotpath)\n\tif ent.IsNotFound(err) || len(alerts) == 0 {\n\t\talertIDs, err := c.CreateAlert(ctx, machineID, []*models.Alert{alertItem})\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"unable to create alert: %w\", err)\n\t\t}\n\n\t\t// happy nilaway\n\t\tif len(alertIDs) == 0 {\n\t\t\treturn \"\", fmt.Errorf(\"unable to create alert: no IDs returned for alert %s\", alertItem.UUID)\n\t\t}\n\n\t\treturn alertIDs[0], nil\n\t}\n\n\t// this should never happen\n\tif len(alerts) > 1 {\n\t\treturn \"\", fmt.Errorf(\"multiple alerts found for uuid %s\", alertItem.UUID)\n\t}\n\n\tlog.Infof(\"Alert %s already exists, checking associated decisions\", alertItem.UUID)\n\n\t// alert is found, check for any missing decisions\n\n\tnewUuids := make([]string, len(alertItem.Decisions))\n\tfor i, decItem := range alertItem.Decisions {\n\t\tnewUuids[i] = decItem.UUID\n\t}\n\n\tfoundAlert := alerts[0]\n\tfoundUuids := make([]string, len(foundAlert.Edges.Decisions))\n\n\tfor i, decItem := range foundAlert.Edges.Decisions {\n\t\tfoundUuids[i] = decItem.UUID\n\t}\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/alerts.go#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"Databases populated by old crowdsec versions before strict uniqueness, bulk imports from CAPI sync gone wrong, or hand-edited SQLite files. Rare in practice.","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"],"exampleFix":"// sqlite cleanup (backup first!)\n// before: two rows share the uuid\n// after: keep the oldest row\nDELETE FROM alerts\nWHERE uuid = 'xxxxxxxx-...' AND id NOT IN (\n  SELECT MIN(id) FROM alerts WHERE uuid = 'xxxxxxxx-...'\n);","handlingStrategy":"validation","validationCode":"// detect duplicate UUIDs in the DB before pushing updates\nrows, err := db.Query(\"SELECT COUNT(*) FROM alerts WHERE uuid = ?\", alertUUID)\nif err == nil && rows.Next() {\n    var n int; rows.Scan(&n)\n    if n > 1 { return errors.New(\"duplicate alert UUIDs in database; deduplicate first\") }\n}","typeGuard":null,"tryCatchPattern":"id, err := client.CreateOrUpdateAlert(ctx, machineID, alert)\nif err != nil && strings.HasPrefix(err.Error(), \"multiple alerts found for uuid\") {\n    // stop retrying — requires DB-level dedup, not a retry\n    return ErrCorruptAlertTable\n}","preventionTips":["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"],"tags":["database","duplicate","uniqueness","crowdsec"],"backgroundTag":"internal-invariant-violation","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"}