{"record":{"id":"f09fb15a596d1aac","repo":"crowdsecurity/crowdsec","slug":"unable-to-update-bouncer-type-and-version-in-datab","errorCode":null,"errorMessage":"unable to update bouncer type and version in database: %w","messagePattern":"unable to update bouncer type and version in database: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/bouncers.go","lineNumber":167,"sourceCode":"\t\treturn fmt.Errorf(\"unable to update bouncer stream pull in database: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) UpdateBouncerIP(ctx context.Context, ipAddr string, id int) error {\n\t_, err := c.Ent.Bouncer.UpdateOneID(id).SetIPAddress(ipAddr).Save(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to update bouncer ip address in database: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) UpdateBouncerTypeAndVersion(ctx context.Context, bType string, version string, id int) error {\n\t_, err := c.Ent.Bouncer.UpdateOneID(id).SetVersion(version).SetType(bType).Save(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to update bouncer type and version in database: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) QueryBouncersInactiveSince(ctx context.Context, t time.Time) ([]*ent.Bouncer, error) {\n\treturn c.Ent.Bouncer.Query().Where(\n\t\t// poor man's coalesce\n\t\tbouncer.Or(\n\t\t\tbouncer.LastPullLT(t),\n\t\t\tbouncer.And(\n\t\t\t\tbouncer.LastPullIsNil(),\n\t\t\t\tbouncer.CreatedAtLT(t),\n\t\t\t),\n\t\t),\n\t).All(ctx)\n}\n","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/bouncers.go#L149-L185","documentation":"UpdateBouncerTypeAndVersion wraps a failed ent update of a bouncer's type and version columns. Called from the LAPI Middleware so the database reflects the authenticating bouncer's reported type/version; any update failure is wrapped with this message.","triggerScenarios":"Bouncer row deleted concurrently (e.g. by prune), database locked/unreachable, or context cancelled during the UPDATE.","commonSituations":"A newly upgraded bouncer re-authenticates while cscli/prune removes stale entries; SQLite contention on busy LAPI instances.","solutions":["Verify the bouncer entry still exists before/after update (ent.IsNotFound)","Inspect the wrapped driver error and retry transient failures","Check SQLite lock contention and WAL mode","Confirm the middleware's context isn't cancelled by client disconnect"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if n, _ := c.Ent.Bouncer.Query().Where(bouncer.ID(id)).Count(ctx); n == 0 { return }","typeGuard":null,"tryCatchPattern":"if err := c.UpdateBouncerTypeAndVersion(ctx, bType, version, id); err != nil {\n\tlog.Warnf(\"bouncer %d type/version update failed: %v\", id, err)\n}","preventionTips":["Treat this as non-fatal telemetry in middleware; never fail auth on it","Log and retry once on transient errors","Keep prune policies from racing with active bouncers","Update type/version on registration only if updates keep failing"],"tags":["database","ent","bouncers","middleware"],"backgroundTag":"database-write-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"}