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 end

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Ensure the agent runs as root or with CAP_NET_ADMIN+CAP_NET_MODULE.
  2. Pre-load the modules: `modprobe ip_set ip_set_hash_net` (or package them in the image).
  3. Shorten/validate generated ipset names to <=31 chars before calling AddPeerFiltering.
  4. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/3696bc9b68e1fd99. Report an issue: GitHub.