crowdsecurity/crowdsec · error
unable to update machine last pull in database: %w
Error message
unable to update machine last pull in database: %w
What it means
UpdateBouncerLastPull wraps a failed ent update of a bouncer's last_pull timestamp. It calls UpdateOneID(id).SetLastPull(...).Save(ctx); any driver error, missing row, or cancelled context surfaces wrapped in this message. Called by GetDecision after a bouncer pulls decisions.
Source
Thrown at pkg/database/bouncers.go:137
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).
SetLastPull(lastPull).
SetStreamCursor(streamCursor).
Save(ctx)
if err != nil {
return fmt.Errorf("unable to update bouncer stream pull in database: %w", err)
}
return nil
}
func (c *Client) UpdateBouncerIP(ctx context.Context, ipAddr string, id int) error {View on GitHub (pinned to 909b515798)
Solutions
- Confirm the bouncer still exists (it may have been pruned or deleted between auth and update)
- Check for SQLite lock contention from other crowdsec processes; consider WAL mode or retrying
- Inspect the wrapped driver error and retry transient failures
- Verify the request context is not being cancelled early by the HTTP server
Example fix
// before
_, 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)
}
// after
nb, err := c.Ent.Bouncer.UpdateOneID(id).SetLastPull(lastPull).Save(ctx)
if ent.IsNotFound(err) {
return fmt.Errorf("bouncer %d no longer exists", id)
} else if err != nil {
return fmt.Errorf("unable to update machine last pull in database: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before calling: ensure the bouncer exists
exists, err := c.BouncerExistsByID(ctx, id)
if err != nil || !exists { return } Try / catch
if err := c.UpdateBouncerLastPull(ctx, time.Now(), id); err != nil {
if ent.IsNotFound(errors.Unwrap(err)) { /* bouncer pruned; re-register or skip */ }
log.Warnf("last pull update failed: %v", err)
} Prevention
- Re-fetch the bouncer ID from auth result rather than caching stale IDs
- Enable WAL mode for concurrent LAPI traffic
- Treat missing-row errors as 'bouncer pruned' not fatal
- Keep LAPI request contexts alive until DB writes finish
When it happens
Trigger: The bouncer ID no longer exists in the bouncers table, the database is unreachable/locked, or the request context was cancelled before the UPDATE committed.
Common situations: Bouncer deleted by prune while it was still pulling decisions, SQLite 'database is locked' under concurrent LAPI traffic, transient MySQL connection reset.
Related errors
- unable to delete bouncers: %w
- unable to update bouncer stream pull in database: %w
- while getting allowlist %s: %s
- unable to update bouncer ip address in database: %w
- unable to update bouncer type and version in database: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/79cdee5b4da9f9ef.
Report an issue: GitHub.