crowdsecurity/crowdsec · error

creating alert decisions: %w

Error message

creating alert decisions: %w

What it means

This error wraps any failure from the ent ORM bulk-insert of a batch of decision rows (c.Ent.Decision.CreateBulk(...).Save(ctx)) while creating the decisions attached to an alert. It is raised inside the slicetools.Batch callback, so the offending batch is retried/aborted per c.decisionBulkSize. The wrapped ent error usually carries the underlying database driver message (constraint violation, connection drop, context cancellation).

Source

Thrown at pkg/database/alerts.go:178

			SetEndSuffix(rng.End.Sfx).
			SetIPSize(int64(rng.Size())).
			SetValue(*decisionItem.Value).
			SetScope(*decisionItem.Scope).
			SetOrigin(*decisionItem.Origin).
			SetSimulated(*alertItem.Simulated).
			SetUUID(decisionItem.UUID).
			SetOwnerID(foundAlert.ID)

		decisionBuilders = append(decisionBuilders, decisionBuilder)
	}

	// create missing decisions in batches

	decisions := make([]*ent.Decision, 0, len(decisionBuilders))
	if err := slicetools.Batch(ctx, decisionBuilders, c.decisionBulkSize, func(ctx context.Context, b []*ent.DecisionCreate) error {
		ret, err := c.Ent.Decision.CreateBulk(b...).Save(ctx)
		if err != nil {
			return fmt.Errorf("creating alert decisions: %w", err)
		}
		decisions = append(decisions, ret...)
		return nil
	}); err != nil {
		return "", err
	}

	return "", nil
}

// UpdateCommunityBlocklist is called to update either the community blocklist (or other lists the user subscribed to)
// it takes care of creating the new alert with the associated decisions, and it will as well deleted the "older" overlapping decisions:
// 1st pull, you get decisions [1,2,3]. it inserts [1,2,3]
// 2nd pull, you get decisions [1,2,3,4]. it inserts [1,2,3,4] and will try to delete [1,2,3,4] with a different alert ID and same origin
func (c *Client) UpdateCommunityBlocklist(ctx context.Context, alertItem *models.Alert) (int, int, int, error) {
	if alertItem == nil {
		return 0, 0, 0, errors.New("nil alert")
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped error for the driver-level cause (duplicate key, locked db, connection refused) and fix that first
  2. Check database connectivity and that no other crowdsec/cscli process holds a lock on the SQLite file (or run vacuum)
  3. Reduce c.decisionBulkSize if the driver reports 'too many parameters'
  4. Retry the operation; transient DB errors during bulk insert are often resolved on a subsequent pull

Example fix

// before
c.decisionBulkSize = 1000
// after (halve the batch to stay under driver parameter limits)
c.decisionBulkSize = 500
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: sanity-check decisions and DB before the call
for _, d := range alert.Decisions {
    if d.UUID == "" || d.Duration == nil {
        return fmt.Errorf("decision missing uuid/duration")
    }
}
if err := dbPing(ctx); err != nil { return err }

Type guard

func validDecision(d *models.Decision) bool {
    return d != nil && d.UUID != "" && d.Duration != nil && d.Origin != nil
}

Try / catch

id, err := client.SaveAlerts(ctx, alert)
if err != nil {
    var bulk *ent.ValidationError
    if errors.Is(err, ErrBulk) || ent.IsConstraintError(err) {
        // dedupe/skip conflicting decision, retry
    }
    return fmt.Errorf("save alerts: %w", err)
}

Prevention

When it happens

Trigger: Inserting alerts with many decisions when one decision row violates a DB constraint or the database is unreachable, the context is cancelled mid-batch, or a duplicate UUID/unique index conflicts on the decisions table.

Common situations: SQLite database file locked by another crowdsec process or corrupted; PostgreSQL/MySQL connection dropped during a large CAPI pull; batch size larger than the driver's parameter limit; duplicate decision UUIDs pushed by a misbehaving list source.

Related errors


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