netbirdio/netbird · error
create ipset: %w
Error message
create ipset: %w
What it means
The ACL manager needed a new ipset for a ruleset, flushed the old one (tolerating absence), then ipset.Create with TypeHashNet and Replace:true failed at the netlink layer. Create fails when the process lacks CAP_NET_ADMIN, when the ip_set/ip_set_hash_net kernel modules are not loaded, or when the set name is invalid (ipset names are limited to 31 characters). The error wraps the raw netlink errno from ipset-go.
Source
Thrown at client/firewall/iptables/acl_linux.go:140
return []firewall.Rule{&Rule{
ruleID: uuid.New().String(),
ipsetName: ipsetName,
ip: ip.String(),
chain: chain,
specs: specs,
v6: m.v6,
}}, nil
}
if err := m.flushIPSet(ipsetName); err != nil {
if errors.Is(err, ipset.ErrSetNotExist) {
log.Debugf("flush ipset %s before use: %v", ipsetName, err)
} else {
log.Errorf("flush ipset %s before use: %v", ipsetName, err)
}
}
if err := m.createIPSet(ipsetName); err != nil {
return nil, fmt.Errorf("create ipset: %w", err)
}
if err := m.addToIPSet(ipsetName, ip); err != nil {
return nil, fmt.Errorf("add IP to ipset: %w", err)
}
ipList := newIpList(ip.String())
m.ipsetStore.addIpList(ipsetName, ipList)
}
ok, err := m.iptablesClient.Exists(tableFilter, chain, specs...)
if err != nil {
return nil, fmt.Errorf("failed to check rule: %w", err)
}
if ok {
return nil, fmt.Errorf("rule already exists")
}
// Insert DROP rules at the beginning, append ACCEPT rules at the endView on GitHub (pinned to 93e97f4bf1)
Solutions
- Ensure the agent runs as root or with CAP_NET_ADMIN+CAP_NET_MODULE.
- Pre-load the modules: `modprobe ip_set ip_set_hash_net` (or package them in the image).
- Shorten/validate generated ipset names to <=31 chars before calling AddPeerFiltering.
- If ipset support is genuinely unavailable, force the non-ipset code path (the manager already probes support via probeIPSetSupport; check why the probe passed but Create failed, e.g. modules unloaded after startup).
Defensive patterns
Strategy: try-catch
Validate before calling
func checkIPSetPrereqs() error {
if os.Geteuid() != 0 {
return errors.New("ipset CREATE requires root")
}
if _, err := os.Stat("/proc/net/ipset"); err != nil {
return errors.New("ipset kernel support missing (modprobe ip_set)")
}
return nil
} Try / catch
if err := mgr.AddPeerFiltering(...); err != nil {
if strings.Contains(err.Error(), "create ipset") {
// inspect inner netlink error: EPERM -> privileges, ENOENT-ish -> modules
log.Errorf("ipset creation failed; check root and ip_set_hash_net module: %v", err)
return // or fall back to a ruleset without ipset
}
} Prevention
- Pre-load ip_set and ip_set_hash_net at image build time (`modprobe` in the entrypoint or baked into the kernel config).
- Keep generated ipset names within the 31-character ipset limit.
- Grant the daemon CAP_NET_ADMIN and CAP_NET_MODULE in container security contexts.
- Monitor probeIPSetSupport's outcome at startup so the non-ipset fallback is chosen when support is absent.
When it happens
Trigger: First AddPeerFiltering call for a new ruleset while the agent runs unprivileged; a minimal VM/container image where `ip_set` and `ip_set_hash_net` are not modules-loaded; a generated ruleset name longer than 31 chars or containing characters ipset rejects; ipset namespace support disabled on old kernels.
Common situations: Distroless/minimal containers without kmod auto-load and no `modprobe ip_set_hash_net` in the entrypoint; running the binary via a non-root systemd unit; NAT-mode kernels with ipset compiled out; long auto-generated ipset names exceeding the 31-char ipset limit.
Related errors
- add IP to ipset %s: %w
- delete ip from ipset: %w
- create ipset %s: %w
- delete IP from ipset %s: %w
- add IP to ipset: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/3696bc9b68e1fd99.
Report an issue: GitHub.