{"record":{"id":"e891644244788ee3","repo":"crowdsecurity/crowdsec","slug":"error-creating-alert-w-w","errorCode":null,"errorMessage":"error creating alert: %w: %w","messagePattern":"error creating alert: %w: %w","errorType":"exception","errorClass":"BulkError","httpStatus":null,"severity":"error","filePath":"pkg/database/alerts.go","lineNumber":249,"sourceCode":"\t\tSetSourceValue(*alertItem.Source.Value).\n\t\tSetSourceIp(alertItem.Source.IP).\n\t\tSetSourceRange(alertItem.Source.Range).\n\t\tSetSourceAsNumber(alertItem.Source.AsNumber).\n\t\tSetSourceAsName(alertItem.Source.AsName).\n\t\tSetSourceCountry(alertItem.Source.Cn).\n\t\tSetSourceLatitude(alertItem.Source.Latitude).\n\t\tSetSourceLongitude(alertItem.Source.Longitude).\n\t\tSetCapacity(*alertItem.Capacity).\n\t\tSetLeakSpeed(*alertItem.Leakspeed).\n\t\tSetSimulated(*alertItem.Simulated).\n\t\tSetScenarioVersion(*alertItem.ScenarioVersion).\n\t\tSetScenarioHash(*alertItem.ScenarioHash).\n\t\tSetKind(alertItem.Kind).\n\t\tSetRemediation(true) // it's from CAPI, we always have decisions\n\n\talertRef, err := alertB.Save(ctx)\n\tif err != nil {\n\t\treturn 0, 0, 0, fmt.Errorf(\"error creating alert: %w: %w\", err, BulkError)\n\t}\n\n\tif len(alertItem.Decisions) == 0 {\n\t\treturn alertRef.ID, 0, 0, nil\n\t}\n\n\ttxClient, err := c.Ent.Tx(ctx)\n\tif err != nil {\n\t\treturn 0, 0, 0, fmt.Errorf(\"error creating transaction: %w: %w\", err, BulkError)\n\t}\n\n\tdecOrigin := CapiMachineID\n\n\tif *alertItem.Decisions[0].Origin == CapiMachineID || *alertItem.Decisions[0].Origin == CapiListsMachineID {\n\t\tdecOrigin = *alertItem.Decisions[0].Origin\n\t} else {\n\t\tlog.Warningf(\"unexpected origin %s\", *alertItem.Decisions[0].Origin)\n\t}","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/alerts.go#L231-L267","documentation":"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).","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\nalertB := c.Ent.Alert.Create().SetCapacity(*alertItem.Capacity) // panics or fails if nil\n// after\nif alertItem.Capacity != nil {\n    alertB = alertB.SetCapacity(*alertItem.Capacity)\n} else {\n    alertB = alertB.SetCapacity(0)\n}","handlingStrategy":"validation","validationCode":"// pre-validate all pointer fields the builder dereferences\nrequired := map[string]*string{\n    \"scenario\": alert.Scenario, \"message\": alert.Message,\n    \"capacity\": alert.Capacity, \"leakspeed\": alert.Leakspeed,\n    \"scenario_version\": alert.ScenarioVersion, \"scenario_hash\": alert.ScenarioHash,\n}\nfor k, v := range required {\n    if v == nil { return fmt.Errorf(\"alert missing %s\", k) }\n}\nif alert.Source == nil || alert.Source.Scope == nil || alert.Source.Value == nil {\n    return errors.New(\"alert missing source scope/value\")\n}","typeGuard":"func alertInsertable(a *models.Alert) bool {\n    return a != nil && a.Scenario != nil && a.Message != nil && a.EventsCount != nil &&\n        a.Source != nil && a.Source.Scope != nil && a.Source.Value != nil &&\n        a.Capacity != nil && a.Leakspeed != nil && a.Simulated != nil &&\n        a.ScenarioVersion != nil && a.ScenarioHash != nil\n}","tryCatchPattern":"if _, _, _, err := db.UpdateCommunityBlocklist(ctx, alert); err != nil {\n    if errors.Is(err, database.BulkError) || ent.IsConstraintError(err) {\n        log.Warnf(\"dropping malformed alert: %v\", err)\n        return nil\n    }\n    return err\n}","preventionTips":["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"],"tags":["database","ent","insert"],"backgroundTag":"database-write-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}