{"record":{"id":"6bc0006e0c4dbb10","repo":"crowdsecurity/crowdsec","slug":"unable-to-delete-bouncers-w","errorCode":null,"errorMessage":"unable to delete bouncers: %w","messagePattern":"unable to delete bouncers: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/bouncers.go","lineNumber":126,"sourceCode":"\t\treturn err\n\t}\n\n\tif nbDeleted == 0 {\n\t\treturn &BouncerNotFoundError{BouncerName: name}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) BulkDeleteBouncers(ctx context.Context, bouncers []*ent.Bouncer) (int, error) {\n\tids := make([]int, len(bouncers))\n\tfor i, b := range bouncers {\n\t\tids[i] = b.ID\n\t}\n\n\tnbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)\n\tif err != nil {\n\t\treturn nbDeleted, fmt.Errorf(\"unable to delete bouncers: %w\", err)\n\t}\n\n\treturn nbDeleted, nil\n}\n\nfunc (c *Client) UpdateBouncerLastPull(ctx context.Context, lastPull time.Time, id int) error {\n\t_, err := c.Ent.Bouncer.UpdateOneID(id).\n\t\tSetLastPull(lastPull).\n\t\tSave(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to update machine last pull in database: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) UpdateBouncerStreamPull(ctx context.Context, lastPull time.Time, streamCursor int, id int) error {\n\t_, err := c.Ent.Bouncer.UpdateOneID(id).","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/bouncers.go#L108-L144","documentation":"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.","triggerScenarios":"Database unavailable/corrupted, context cancelled during delete, foreign key or driver constraint failure while removing the bouncer IDs gathered by QueryBouncers.","commonSituations":"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.","solutions":["Check database connectivity and that no other process holds a lock on the SQLite file","Inspect the wrapped %w error for the driver-level cause (retry on transient network errors)","Verify the context (timeout/cancellation) is generous enough for batch deletes","Run database integrity checks / backup-restore if the DB is corrupted"],"exampleFix":"// before\nnbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)\n// after\nnbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)\nif ent.IsNotFound(err) {\n\treturn nbDeleted, nil // nothing left to delete\n}","handlingStrategy":"retry","validationCode":"// caller-side: verify DB reachable before bulk delete\nif err := client.PingDB(ctx); err != nil { return fmt.Errorf(\"db unavailable: %w\", err) }","typeGuard":null,"tryCatchPattern":"nbDeleted, err := c.BulkDeleteBouncers(ctx, bouncers)\nif err != nil {\n\tvar rec errtypes.ErrRetryable\n\tif errors.As(err, &rec) { /* retry with backoff */ }\n\treturn fmt.Errorf(\"prune aborted: %w\", err)\n}","preventionTips":["Keep prune contexts generous; avoid cancelling mid-batch","Enable SQLite WAL mode to reduce lock contention","Monitor DB connectivity before maintenance jobs","Backup the DB before bulk deletes"],"tags":["database","ent","sqlite","bouncers"],"backgroundTag":"database-query-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"}