crowdsecurity/crowdsec · error

unable to delete bouncers: %w

Error message

unable to delete bouncers: %w

What it means

BulkDeleteBouncers wraps a failed ent batch delete of bouncer rows. The delete runs `DELETE FROM bouncers WHERE id IN (...)` against the configured database; any driver-level or context failure is wrapped with this message. Callers (e.g. prune) get the count plus this error.

Source

Thrown at pkg/database/bouncers.go:126

		return err
	}

	if nbDeleted == 0 {
		return &BouncerNotFoundError{BouncerName: name}
	}

	return nil
}

func (c *Client) BulkDeleteBouncers(ctx context.Context, bouncers []*ent.Bouncer) (int, error) {
	ids := make([]int, len(bouncers))
	for i, b := range bouncers {
		ids[i] = b.ID
	}

	nbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)
	if err != nil {
		return nbDeleted, fmt.Errorf("unable to delete bouncers: %w", err)
	}

	return nbDeleted, nil
}

func (c *Client) UpdateBouncerLastPull(ctx context.Context, lastPull time.Time, id int) error {
	_, err := c.Ent.Bouncer.UpdateOneID(id).
		SetLastPull(lastPull).
		Save(ctx)
	if err != nil {
		return fmt.Errorf("unable to update machine last pull in database: %w", err)
	}

	return nil
}

func (c *Client) UpdateBouncerStreamPull(ctx context.Context, lastPull time.Time, streamCursor int, id int) error {
	_, err := c.Ent.Bouncer.UpdateOneID(id).

View on GitHub (pinned to 909b515798)

Solutions

  1. Check database connectivity and that no other process holds a lock on the SQLite file
  2. Inspect the wrapped %w error for the driver-level cause (retry on transient network errors)
  3. Verify the context (timeout/cancellation) is generous enough for batch deletes
  4. Run database integrity checks / backup-restore if the DB is corrupted

Example fix

// before
nbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)
// after
nbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)
if ent.IsNotFound(err) {
	return nbDeleted, nil // nothing left to delete
}
Defensive patterns

Strategy: retry

Validate before calling

// caller-side: verify DB reachable before bulk delete
if err := client.PingDB(ctx); err != nil { return fmt.Errorf("db unavailable: %w", err) }

Try / catch

nbDeleted, err := c.BulkDeleteBouncers(ctx, bouncers)
if err != nil {
	var rec errtypes.ErrRetryable
	if errors.As(err, &rec) { /* retry with backoff */ }
	return fmt.Errorf("prune aborted: %w", err)
}

Prevention

When it happens

Trigger: Database unavailable/corrupted, context cancelled during delete, foreign key or driver constraint failure while removing the bouncer IDs gathered by QueryBouncers.

Common situations: cscli/prune deleting stale bouncers when the SQLite file is locked by another process, MySQL connection dropped mid-batch, context deadline exceeded on slow disks.

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/6bc0006e0c4dbb10. Report an issue: GitHub.