crowdsecurity/crowdsec · error
unable to create alert: %w
Error message
unable to create alert: %w
What it means
After the lookup shows the alert is absent, CreateOrUpdateAlert calls CreateAlert to insert it (with its events and decisions, in bulk transactions). If CreateAlert fails for any reason, the error is wrapped as 'unable to create alert: %w'. The underlying cause is usually a transactional insert failure surfaced through rollbackOnError (error 890).
Source
Thrown at pkg/database/alerts.go:59
// CreateOrUpdateAlert is specific to PAPI : It checks if alert already exists, otherwise inserts it
// if alert already exists, it checks it associated decisions already exists
// if some associated decisions are missing (ie. previous insert ended up in error) it inserts them
func (c *Client) CreateOrUpdateAlert(ctx context.Context, machineID string, alertItem *models.Alert) (string, error) {
if alertItem.UUID == "" {
return "", errors.New("alert UUID is empty")
}
alerts, err := c.Ent.Alert.Query().Where(alert.UUID(alertItem.UUID)).WithDecisions().All(ctx)
if err != nil && !ent.IsNotFound(err) {
return "", fmt.Errorf("unable to query alerts for uuid %s: %w", alertItem.UUID, err)
}
// 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 decisionsView on GitHub (pinned to 909b515798)
Solutions
- Unwrap the error to identify the CreateAlert cause (lock, constraint, validation)
- For SQLite lock errors, stagger writers or migrate to PostgreSQL/MySQL
- Validate the alert payload (decision UUIDs, scope/value fields) before pushing
- Retry: the lookup-by-UUID makes the operation idempotent, so a retry after a transient failure is safe
Example fix
// before: fire-and-forget push
// after: retry transient insert failures
id, err := client.CreateOrUpdateAlert(ctx, machineID, alert)
if err != nil && isTransient(err) {
time.Sleep(backoff)
id, err = client.CreateOrUpdateAlert(ctx, machineID, alert)
} Defensive patterns
Strategy: retry
Validate before calling
// validate payload before insert
for _, d := range alertItem.Decisions {
if d.UUID == "" || d.Value == nil || *d.Value == "" {
return errors.New("invalid decision in alert payload")
}
}
if alertItem.UUID == "" { return errors.New("alert UUID is empty") } Try / catch
id, err := client.CreateOrUpdateAlert(ctx, machineID, alert)
if err != nil && strings.HasPrefix(err.Error(), "unable to create alert:") && !strings.Contains(err.Error(), "no IDs") {
time.Sleep(retryBackoff)
id, err = client.CreateOrUpdateAlert(ctx, machineID, alert) // idempotent by UUID
} Prevention
- Validate decisions (UUID, type, value, duration) before pushing to LAPI
- Don't send duplicate alerts concurrently — dedupe by UUID client-side
- Use a server DB backend under concurrent load
- Watch for SQLite lock logs and address contention early
When it happens
Trigger: c.CreateAlert(ctx, machineID, []*models.Alert{alertItem}) returns an error during a PAPI alert push — typically a failed bulk insert (DB locked, constraint violation, oversized payload, malformed decision source range) — while the alert UUID was confirmed not already present.
Common situations: Concurrent LAPI writes locking SQLite; alert payload with invalid IP/range strings in decisions; decisions referencing malformed metadata; disk full; version mismatch causing schema mismatch during insert.
Related errors
- unable to insert bulk
- %s: %w
- creating alert transaction: %w: %w
- no database configuration provided
- unable to update
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/b5a0cc32e3459433.
Report an issue: GitHub.