crowdsecurity/crowdsec · error

unable to add values to allowlist: %w

Error message

unable to add values to allowlist: %w

What it means

ReplaceAllowlist first deletes all existing items of an allowlist, then re-adds the new set via AddToAllowlist. When the re-insert phase fails (DB insert error, invalid value, constraint violation), the deletion has already committed, so the error means the allowlist may be left empty. It wraps the underlying ent/SQLite error with this message.

Source

Thrown at pkg/database/allowlists.go:229

	if err != nil {
		return fmt.Errorf("unable to update allowlist: %w", err)
	}

	return nil
}

func (c *Client) ReplaceAllowlist(ctx context.Context, list *ent.AllowList, items []*models.AllowlistItem, fromConsole bool) (int, error) {
	c.Log.Debugf("replacing values in allowlist %s", list.Name)
	c.Log.Tracef("items: %+v", items)

	_, err := c.Ent.AllowListItem.Delete().Where(allowlistitem.HasAllowlistWith(allowlist.IDEQ(list.ID))).Exec(ctx)
	if err != nil {
		return 0, fmt.Errorf("unable to delete allowlist contents: %w", err)
	}

	added, err := c.AddToAllowlist(ctx, list, items)
	if err != nil {
		return 0, fmt.Errorf("unable to add values to allowlist: %w", err)
	}

	if !list.FromConsole && fromConsole {
		c.Log.Infof("marking allowlist %s as managed from console and replacing its content", list.Name)

		err = c.Ent.AllowList.Update().SetFromConsole(fromConsole).Where(allowlist.IDEQ(list.ID)).Exec(ctx)
		if err != nil {
			return 0, fmt.Errorf("unable to update allowlist: %w", err)
		}
	}

	return added, nil
}

// IsAllowlistedBy returns a list of human-readable reasons explaining which allowlists
// the given value (IP or CIDR) matches.
//
// Few cases:

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped error (%w) to find the root cause - usually a DB constraint or lock error
  2. Verify the incoming AllowlistItem values are valid IPs/CIDRs before calling ReplaceAllowlist
  3. Check for concurrent crowdsec/cscli processes holding the SQLite lock; stop others and retry
  4. Re-run ReplaceAllowlist: it is idempotent since it deletes then re-adds all items

Example fix

// before
c.Log.Debugf("replacing values in allowlist %s", list.Name)
added, err := c.AddToAllowlist(ctx, list, items)
// after - validate values first so a bad item does not empty the list
for _, it := range items {
    if _, err := csnet.NewRange(it.Value); err != nil {
        return 0, fmt.Errorf("invalid allowlist value %q: %w", it.Value, err)
    }
}
added, err := c.AddToAllowlist(ctx, list, items)
Defensive patterns

Strategy: try-catch

Validate before calling

for _, it := range items {
    if _, err := csnet.NewRange(it.Value); err != nil {
        return fmt.Errorf("invalid allowlist value %q: %w", it.Value, err)
    }
}

Try / catch

added, err := c.ReplaceAllowlist(ctx, list, items, fromConsole)
if err != nil {
    if strings.Contains(err.Error(), "database is locked") {
        // back off and retry the whole replace; it is idempotent
    }
    return fmt.Errorf("replace allowlist %s failed, list may be empty: %w", list.Name, err)
}

Prevention

When it happens

Trigger: Calling ReplaceAllowlist (e.g. via updateOneAllowlist when the console pulls allowlist updates) where AddToAllowlist fails: malformed allowlist item value that fails parsing, duplicate value hitting a uniqueness constraint, or the database being locked/unavailable.

Common situations: Console-managed allowlist sync pulling items with unexpected formats; concurrent crowdsec processes writing to the SQLite DB causing 'database is locked'; a corrupted DB schema after an upgrade.

Related errors


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