crowdsecurity/crowdsec · error · BulkError
creating alert transaction: %w: %w
Error message
creating alert transaction: %w: %w
What it means
createAlertBatch opens a database transaction (c.Ent.Tx(ctx)) before building and saving all alerts in the batch. This error wraps a failure to start that transaction, tagged with the BulkError sentinel. It is an infrastructure-level failure — the driver refused BEGIN — so no alert work was attempted.
Source
Thrown at pkg/database/alerts.go:636
return err
})
}); err != nil {
return nil, fmt.Errorf("attach decisions to alert %d: %w", a.ID, err)
}
}
return ret, nil
}
type alertCreatePlan struct {
builder *ent.AlertCreate
decisions []*ent.Decision
}
func (c *Client) createAlertBatch(ctx context.Context, machineID string, owner *ent.Machine, alerts []*models.Alert) ([]string, error) {
tx, err := c.Ent.Tx(ctx)
if err != nil {
return nil, fmt.Errorf("creating alert transaction: %w: %w", err, BulkError)
}
txEnt := tx.Client()
batch := make([]alertCreatePlan, 0, len(alerts))
for _, alertItem := range alerts {
startAtTime, stopAtTime := parseAlertTimes(alertItem, c.Log)
// display proper alert in logs
for _, disp := range alertItem.FormatAsStrings(machineID, log.StandardLogger()) {
c.Log.Info(disp)
}
events, err := buildEventCreates(ctx, c.Log, txEnt, machineID, alertItem)
if err != nil {
return nil, rollbackOnError(tx, err, fmt.Sprintf("building events for alert %s", alertItem.UUID))
}View on GitHub (pinned to 909b515798)
Solutions
- Check the wrapped driver error: if the connection is down, verify DB host/credentials in crowdsec.yaml and that the DB server is running
- If SQLite is locked, ensure the file is on a local filesystem and no other process holds a write lock; restart crowdsec if the pool is wedged
- If the context was cancelled, increase the client/HTTP timeout that cancelled the request and retry
- On MySQL/Postgres 'too many connections', raise max_connections or reduce crowdsec concurrency/pool size
- Verify disk space and file permissions on the SQLite database path
Example fix
// before
ids, err := client.CreateAlert(ctx, machineID, alerts)
if err != nil {
return err
}
// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
ids, err := client.CreateAlert(ctx, machineID, alerts)
if err != nil {
if isConnError(err) {
// reconnect / check DB availability before retrying
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
if err := ctx.Err(); err != nil {
return fmt.Errorf("context already cancelled: %w", err) // avoid doomed call
} Type guard
null
Try / catch
ids, err := client.CreateAlert(ctx, machineID, alerts)
if err != nil && strings.Contains(err.Error(), "creating alert transaction") {
// DB unreachable/locked: check connectivity, then retry with fresh context
return retryWithBackoff(func() error {
ids, err = client.CreateAlert(ctx, machineID, alerts)
return err
})
} Prevention
- Give LAPI/alert-creation calls a generous but finite context timeout
- Verify DB connectivity settings in crowdsec.yaml before bulk operations
- Keep the SQLite DB on local storage with correct file permissions
- On MySQL/Postgres, size the connection pool below the server's max_connections
- Retry with backoff: transaction start is fully idempotent
When it happens
Trigger: c.Ent.Tx(ctx) fails because the database connection is down or pooled out, the driver cannot begin a transaction (SQLite file locked/unreadable, MySQL 'max_connections' reached, server gone away), or the context is already cancelled/expired.
Common situations: SQLite DB file on NFS or with wrong permissions preventing locking; MySQL/Postgres connection pool exhausted under load; database restarted mid-run; request context cancelled by an LAPI client timeout before the transaction began.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/fc4f835e6164afc0.
Report an issue: GitHub.