crowdsecurity/crowdsec · error

unable to update bouncer stream pull in database: %w

Error message

unable to update bouncer stream pull in database: %w

What it means

UpdateBouncerStreamPull wraps a failed ent update setting last_pull and the stream cursor on a bouncer row. Same mechanics as the last-pull update but also persists streamCursor; failures are wrapped with this message. Called by StreamDecision.

Source

Thrown at pkg/database/bouncers.go:149

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 {
	_, err := c.Ent.Bouncer.UpdateOneID(id).SetIPAddress(ipAddr).Save(ctx)
	if err != nil {
		return fmt.Errorf("unable to update bouncer ip address in database: %w", err)
	}

	return nil
}

func (c *Client) UpdateBouncerTypeAndVersion(ctx context.Context, bType string, version string, id int) error {
	_, err := c.Ent.Bouncer.UpdateOneID(id).SetVersion(version).SetType(bType).Save(ctx)
	if err != nil {
		return fmt.Errorf("unable to update bouncer type and version in database: %w", err)

View on GitHub (pinned to 909b515798)

Solutions

  1. Check SQLite lock contention / enable WAL mode for concurrent stream bouncers
  2. Verify the bouncer was not deleted concurrently (ent.IsNotFound on the wrapped error)
  3. Retry the update on transient driver errors
  4. Ensure the request context survives the stream handler duration
Defensive patterns

Strategy: retry

Validate before calling

// ensure bouncer still exists before stream-cursor update
if n, _ := c.Ent.Bouncer.Query().Where(bouncer.ID(id)).Count(ctx); n == 0 { return }

Try / catch

err := c.UpdateBouncerStreamPull(ctx, lastPull, cursor, id)
if errors.Is(errors.Unwrap(err), sqlite.ErrLocked) {
	time.Sleep(backoff); retry()
}

Prevention

When it happens

Trigger: Bouncer row missing (deleted concurrently), database locked or unreachable, context cancelled mid-update.

Common situations: Stream-mode bouncers polling frequently on a busy SQLite file hitting 'database is locked'; bouncer pruned while its stream session is live.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/5beb9d4bcc4c7494. Report an issue: GitHub.