{"record":{"id":"3138fae6f8e53b6f","repo":"crowdsecurity/crowdsec","slug":"unable-to-update-bouncer-ip-address-in-database","errorCode":null,"errorMessage":"unable to update bouncer ip address in database: %w","messagePattern":"unable to update bouncer ip address in database: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/bouncers.go","lineNumber":158,"sourceCode":"\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).\n\t\tSetLastPull(lastPull).\n\t\tSetStreamCursor(streamCursor).\n\t\tSave(ctx)\n\tif err != nil {\n\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(","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/bouncers.go#L140-L176","documentation":"UpdateBouncerIP wraps a failed ent update of a bouncer's ip_address column. UpdateOneID(id).SetIPAddress(ipAddr).Save(ctx) fails on driver errors, missing rows, or cancelled contexts and is wrapped with this message. Called from the LAPI Middleware when a bouncer authenticates.","triggerScenarios":"Bouncer ID no longer exists, database unavailable or locked, or the IP string violates a column constraint; also fires when context is cancelled.","commonSituations":"Bouncer pruned between authentication and the middleware update; 'database is locked' under load; IPv6-mapped addresses being written to a constrained column.","solutions":["Confirm the bouncer still exists (check cscli bouncers list)","Retry the update; inspect the wrapped driver error for the real cause","Check SQLite locking/WAL configuration under concurrent access","Validate the IP string format before persisting"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if net.ParseIP(ipAddr) == nil { return errors.New(\"invalid bouncer IP\") }","typeGuard":null,"tryCatchPattern":"if err := c.UpdateBouncerIP(ctx, ip, id); err != nil {\n\tif ent.IsNotFound(errors.Unwrap(err)) { return middleware.ErrBouncerDeleted }\n\treturn fmt.Errorf(\"middleware bouncer ip update: %w\", err)\n}","preventionTips":["Normalize the IP (RemoteAddr host part) before persisting","Don't prune bouncers on every startup without grace period","Retry transient driver errors in middleware","Validate ipAddr with net.ParseIP first"],"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-14T00:17:10.932Z"}