crowdsecurity/crowdsec · warning

unable to update base bouncer metrics in database: %w

Error message

unable to update base bouncer metrics in database: %w

What it means

BouncerUpdateBaseMetrics persists bouncer telemetry (OS family/version, feature flags, bouncer type) via an ent Bouncer update. If the Save fails, this error wraps the DB failure. The bouncer's auth still works; only metrics recording failed.

Source

Thrown at pkg/database/bouncers.go:37

	return fmt.Sprintf("'%s' does not exist", e.BouncerName)
}

func (c *Client) BouncerUpdateBaseMetrics(ctx context.Context, bouncerName string, bouncerType string, baseMetrics models.BaseMetrics) error {
	os := baseMetrics.Os
	features := strings.Join(baseMetrics.FeatureFlags, ",")

	_, err := c.Ent.Bouncer.
		Update().
		Where(bouncer.NameEQ(bouncerName)).
		SetNillableVersion(baseMetrics.Version).
		SetOsname(*os.Name).
		SetOsfamily(os.Family).
		SetOsversion(*os.Version).
		SetFeatureflags(features).
		SetType(bouncerType).
		Save(ctx)
	if err != nil {
		return fmt.Errorf("unable to update base bouncer metrics in database: %w", err)
	}

	return nil
}

func (c *Client) SelectBouncers(ctx context.Context, apiKeyHash string, authType string) ([]*ent.Bouncer, error) {
	// Order by ID so manually created bouncer will be first in the list to use as the base name
	// when automatically creating a new entry if API keys are shared
	result, err := c.Ent.Bouncer.Query().Where(bouncer.APIKeyEQ(apiKeyHash), bouncer.AuthTypeEQ(authType)).Order(ent.Asc(bouncer.FieldID)).All(ctx)
	if err != nil {
		return nil, err
	}

	return result, nil
}

func (c *Client) SelectBouncerWithIP(ctx context.Context, apiKeyHash string, clientIP string) (*ent.Bouncer, error) {
	result, err := c.Ent.Bouncer.Query().Where(bouncer.APIKeyEQ(apiKeyHash), bouncer.IPAddressEQ(clientIP)).First(ctx)

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify the bouncer still exists ('cscli bouncers list'); re-auth re-creates missing rows
  2. Check the wrapped error for 'database is locked' and reduce concurrent writers
  3. Have the bouncer re-authenticate - metrics update is retried on each auth
Defensive patterns

Strategy: fallback

Validate before calling

if _, err := c.SelectBouncers(ctx, apiKeyHash, authType); err != nil {
    // bouncer row gone; auth flow will re-create it before metrics update
}

Try / catch

if err := c.BouncerUpdateBaseMetrics(ctx, bouncerID, os, features, bouncerType); err != nil {
    c.Log.Warnf("bouncer metrics update failed (auth unaffected): %v", err)
    return nil // do not fail authentication for a metrics bookkeeping error
}

Prevention

When it happens

Trigger: Calling BouncerUpdateBaseMetrics (from updateBaseMetrics, on bouncer auth) when the ent update fails: the bouncer row was deleted concurrently, DB locked, or IO error.

Common situations: A bouncer authenticating at the same moment an admin deletes it via 'cscli bouncers delete'; heavy SQLite write load from the daemon.

Related errors


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