crowdsecurity/crowdsec · error · BulkError
error creating alert: %w: %w
Error message
error creating alert: %w: %w
What it means
c.Ent.Alert.Create()....Save(ctx) failed while persisting the alert row itself, before any decisions are written; the error is wrapped with the BulkError sentinel so callers can classify it as a bulk/insert-stage failure. The wrapped ent error contains the driver-level reason (constraint, connection, cancellation).
Source
Thrown at pkg/database/alerts.go:249
SetSourceValue(*alertItem.Source.Value).
SetSourceIp(alertItem.Source.IP).
SetSourceRange(alertItem.Source.Range).
SetSourceAsNumber(alertItem.Source.AsNumber).
SetSourceAsName(alertItem.Source.AsName).
SetSourceCountry(alertItem.Source.Cn).
SetSourceLatitude(alertItem.Source.Latitude).
SetSourceLongitude(alertItem.Source.Longitude).
SetCapacity(*alertItem.Capacity).
SetLeakSpeed(*alertItem.Leakspeed).
SetSimulated(*alertItem.Simulated).
SetScenarioVersion(*alertItem.ScenarioVersion).
SetScenarioHash(*alertItem.ScenarioHash).
SetKind(alertItem.Kind).
SetRemediation(true) // it's from CAPI, we always have decisions
alertRef, err := alertB.Save(ctx)
if err != nil {
return 0, 0, 0, fmt.Errorf("error creating alert: %w: %w", err, BulkError)
}
if len(alertItem.Decisions) == 0 {
return alertRef.ID, 0, 0, nil
}
txClient, err := c.Ent.Tx(ctx)
if err != nil {
return 0, 0, 0, fmt.Errorf("error creating transaction: %w: %w", err, BulkError)
}
decOrigin := CapiMachineID
if *alertItem.Decisions[0].Origin == CapiMachineID || *alertItem.Decisions[0].Origin == CapiListsMachineID {
decOrigin = *alertItem.Decisions[0].Origin
} else {
log.Warningf("unexpected origin %s", *alertItem.Decisions[0].Origin)
}View on GitHub (pinned to 909b515798)
Solutions
- Read the wrapped error: a NOT NULL/constraint violation points to a nil or empty field in the incoming models.Alert — validate/populate it before SaveAlerts
- Check DB availability and schema version (cscli version, database migration status)
- If SQLite is locked, stop concurrent crowdsec/cscli instances or move to a client-server DB
- Retry on transient connection errors; the CAPI pull will re-deliver the alert
Example fix
// before
alertB := c.Ent.Alert.Create().SetCapacity(*alertItem.Capacity) // panics or fails if nil
// after
if alertItem.Capacity != nil {
alertB = alertB.SetCapacity(*alertItem.Capacity)
} else {
alertB = alertB.SetCapacity(0)
} Defensive patterns
Strategy: validation
Validate before calling
// pre-validate all pointer fields the builder dereferences
required := map[string]*string{
"scenario": alert.Scenario, "message": alert.Message,
"capacity": alert.Capacity, "leakspeed": alert.Leakspeed,
"scenario_version": alert.ScenarioVersion, "scenario_hash": alert.ScenarioHash,
}
for k, v := range required {
if v == nil { return fmt.Errorf("alert missing %s", k) }
}
if alert.Source == nil || alert.Source.Scope == nil || alert.Source.Value == nil {
return errors.New("alert missing source scope/value")
} Type guard
func alertInsertable(a *models.Alert) bool {
return a != nil && a.Scenario != nil && a.Message != nil && a.EventsCount != nil &&
a.Source != nil && a.Source.Scope != nil && a.Source.Value != nil &&
a.Capacity != nil && a.Leakspeed != nil && a.Simulated != nil &&
a.ScenarioVersion != nil && a.ScenarioHash != nil
} Try / catch
if _, _, _, err := db.UpdateCommunityBlocklist(ctx, alert); err != nil {
if errors.Is(err, database.BulkError) || ent.IsConstraintError(err) {
log.Warnf("dropping malformed alert: %v", err)
return nil
}
return err
} Prevention
- Validate incoming CAPI/list alert payloads before SaveAlerts
- Keep the DB schema migrated after upgrades (restart crowdsec to run migrations)
- Avoid concurrent writers on SQLite; prefer PostgreSQL for many-writer setups
When it happens
Trigger: Calling UpdateCommunityBlocklist (via SaveAlerts) when the alerts table insert fails: NOT NULL constraint on a field whose pointer in alertItem is nil (Scenario, Message, EventsCount, Source, Capacity, Leakspeed, Simulated, ScenarioVersion, ScenarioHash are all dereferenced without nil checks), or the database is down.
Common situations: A CAPI or custom list alert is missing optional-looking fields that the builder dereferences (e.g. nil Capacity or Source.Scope causes a panic or NOT NULL violation); SQLite file locked/corrupted; DB schema out of date after an upgrade (run cscli migrate / restart so migrations apply).
Related errors
- unable to create bouncer: %w
- unable to insert bulk
- while getting allowlist %s: %s
- while getting alert: %w
- while getting decision: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/e891644244788ee3.
Report an issue: GitHub.