{"record":{"id":"ee416c1667ab54e6","repo":"crowdsecurity/crowdsec","slug":"unable-to-add-values-to-allowlist-w","errorCode":null,"errorMessage":"unable to add values to allowlist: %w","messagePattern":"unable to add values to allowlist: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/allowlists.go","lineNumber":229,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to update allowlist: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) ReplaceAllowlist(ctx context.Context, list *ent.AllowList, items []*models.AllowlistItem, fromConsole bool) (int, error) {\n\tc.Log.Debugf(\"replacing values in allowlist %s\", list.Name)\n\tc.Log.Tracef(\"items: %+v\", items)\n\n\t_, err := c.Ent.AllowListItem.Delete().Where(allowlistitem.HasAllowlistWith(allowlist.IDEQ(list.ID))).Exec(ctx)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"unable to delete allowlist contents: %w\", err)\n\t}\n\n\tadded, err := c.AddToAllowlist(ctx, list, items)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"unable to add values to allowlist: %w\", err)\n\t}\n\n\tif !list.FromConsole && fromConsole {\n\t\tc.Log.Infof(\"marking allowlist %s as managed from console and replacing its content\", list.Name)\n\n\t\terr = c.Ent.AllowList.Update().SetFromConsole(fromConsole).Where(allowlist.IDEQ(list.ID)).Exec(ctx)\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"unable to update allowlist: %w\", err)\n\t\t}\n\t}\n\n\treturn added, nil\n}\n\n// IsAllowlistedBy returns a list of human-readable reasons explaining which allowlists\n// the given value (IP or CIDR) matches.\n//\n// Few cases:","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/allowlists.go#L211-L247","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped error (%w) to find the root cause - usually a DB constraint or lock error","Verify the incoming AllowlistItem values are valid IPs/CIDRs before calling ReplaceAllowlist","Check for concurrent crowdsec/cscli processes holding the SQLite lock; stop others and retry","Re-run ReplaceAllowlist: it is idempotent since it deletes then re-adds all items"],"exampleFix":"// before\nc.Log.Debugf(\"replacing values in allowlist %s\", list.Name)\nadded, err := c.AddToAllowlist(ctx, list, items)\n// after - validate values first so a bad item does not empty the list\nfor _, it := range items {\n    if _, err := csnet.NewRange(it.Value); err != nil {\n        return 0, fmt.Errorf(\"invalid allowlist value %q: %w\", it.Value, err)\n    }\n}\nadded, err := c.AddToAllowlist(ctx, list, items)","handlingStrategy":"try-catch","validationCode":"for _, it := range items {\n    if _, err := csnet.NewRange(it.Value); err != nil {\n        return fmt.Errorf(\"invalid allowlist value %q: %w\", it.Value, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"added, err := c.ReplaceAllowlist(ctx, list, items, fromConsole)\nif err != nil {\n    if strings.Contains(err.Error(), \"database is locked\") {\n        // back off and retry the whole replace; it is idempotent\n    }\n    return fmt.Errorf(\"replace allowlist %s failed, list may be empty: %w\", list.Name, err)\n}","preventionTips":["Validate item values are parseable IPs/CIDRs before calling ReplaceAllowlist","Avoid running concurrent cscli writes and daemon allowlist syncs on SQLite","Treat a failed replace as potentially destructive: re-run it rather than leaving the list empty"],"tags":["database","allowlist","sqlite","crowdsec"],"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-14T05:17:10.506Z"}