crowdsecurity/crowdsec · error

while saving alert from %s: %w

Error message

while saving alert from %s: %w

What it means

SaveAlerts wraps the error returned by dbClient.UpdateCommunityBlocklist when persisting a CAPI community-blocklist alert and its decisions. The inner error comes from the database layer (constraint violations, DB unavailable, context cancelled).

Source

Thrown at pkg/apiserver/apic.go:891

		decisions[outIdx] = decision
		outIdx++
	}
	// shrink the list, those are deleted items
	return decisions[:outIdx]
}

func (a *apic) SaveAlerts(ctx context.Context, alertsFromCapi []*models.Alert, addCounters map[string]map[string]int, deleteCounters map[string]map[string]int) error {
	for _, alert := range alertsFromCapi {
		setAlertScenario(alert, addCounters, deleteCounters)
		log.Debugf("%s has %d decisions", *alert.Source.Scope, len(alert.Decisions))

		if a.dbClient.Type == "sqlite" && (a.dbClient.WalMode == nil || !*a.dbClient.WalMode) {
			log.Warningf("sqlite is not using WAL mode, LAPI might become unresponsive when inserting the community blocklist")
		}

		alertID, inserted, deleted, err := a.dbClient.UpdateCommunityBlocklist(ctx, alert)
		if err != nil {
			return fmt.Errorf("while saving alert from %s: %w", *alert.Source.Scope, err)
		}

		log.Printf("%s : added %d entries, deleted %d entries (alert:%d)", *alert.Source.Scope, inserted, deleted, alertID)
	}

	return nil
}

func (a *apic) ShouldForcePullBlocklist(ctx context.Context, blocklist *modelscapi.BlocklistLink) (bool, error) {
	// we should force pull if the blocklist decisions are about to expire or there's no decision in the db
	alertQuery := a.dbClient.Ent.Alert.Query()
	alertQuery.Where(alert.SourceScopeEQ(fmt.Sprintf("%s:%s", types.ListOrigin, *blocklist.Name)))
	alertQuery.Order(ent.Desc(alert.FieldCreatedAt))

	alertInstance, err := alertQuery.First(ctx)
	if err != nil {
		if ent.IsNotFound(err) {
			log.Debugf("no alert found for %s, force refresh", *blocklist.Name)

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped inner error to identify the DB-layer cause.
  2. Enable WAL mode for SQLite (`cscli db enable-wal`) and run `cscli db doctor`.
  3. Verify DB connectivity and that migrations ran (`cscli db migrate` / restart crowdsec).
  4. Increase pull timeout / check disk space if the error is a timeout or write failure.
Defensive patterns

Strategy: try-catch

Validate before calling

// verify DB is reachable before large pulls:
// cscli db doctor && cscli db enable-wal

Try / catch

if err := a.SaveAlerts(ctx, alerts, addCounters, nil); err != nil {
    var dbErr *ent.ConstraintError
    if errors.As(err, &dbErr) { /* handle duplicate/conflict */ }
    return fmt.Errorf("...: %w", err)
}

Prevention

When it happens

Trigger: PullTop or updateBlocklist saves fetched blocklist alerts; UpdateCommunityBlocklist fails, e.g. SQLite locked/corrupted, PostgreSQL down, context deadline exceeded during long CAPI pulls, or a malformed decision from CAPI violating schema.

Common situations: SQLite without WAL mode under concurrent LAPI writes, DB restart during community blocklist pull, disk full, huge community blocklist insert timing out, DB migration not applied after upgrade.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/9175dfbe07ea986b. Report an issue: GitHub.