netbirdio/netbird · error
apply network -s: %w
Error message
apply network -s: %w
What it means
In addNatRule(), applyNetwork("-s", pair.Source, nil) translates the route pair's source into iptables args. A plain prefix needs no syscall, but a network *set* goes through ipsetCounter.Increment(), which creates/refreshes an ipset via ipset-go. The wrapped 'create or get ipset' failure is therefore usually an ipset-level problem (missing ipset support, CAP_NET_ADMIN, or a set name over the kernel's 31-character limit), not an iptables one.
Source
Thrown at client/firewall/iptables/router_linux.go:689
}
markValue := nbnet.PreroutingFwmarkMasquerade
if pair.Inverse {
markValue = nbnet.PreroutingFwmarkMasqueradeReturn
}
rule := []string{"-i", r.wgIface.Name()}
if pair.Inverse {
rule = []string{"!", "-i", r.wgIface.Name()}
}
rule = append(rule,
"-m", "conntrack",
"--ctstate", "NEW",
)
sourceExp, err := r.applyNetwork("-s", pair.Source, nil)
if err != nil {
return fmt.Errorf("apply network -s: %w", err)
}
destExp, err := r.applyNetwork("-d", pair.Destination, nil)
if err != nil {
return fmt.Errorf("apply network -d: %w", err)
}
rule = append(rule, sourceExp...)
rule = append(rule, destExp...)
rule = append(rule,
"-j", "MARK", "--set-mark", fmt.Sprintf("%#x", markValue),
)
// Ensure nat rules come first, so the mark can be overwritten.
// Currently overwritten by the dst-type LOCAL rules for redirected traffic.
if err := r.iptablesClient.Insert(tableMangle, chainRTPRE, 1, rule...); err != nil {
// TODO: rollback ipset counter
return fmt.Errorf("error while adding marking rule for %s: %v", pair.Destination, err)
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Check `lsmod | grep ip_set` and load with `modprobe ip_set ip_set_hash_net`
- Verify the daemon has CAP_NET_ADMIN; in containers also check that netlink is not seccomp-filtered
- Reproduce: `sudo ipset create <name> hash:net family inet` and read the error
- Look at the earlier agent logs for 'create or get ipset' with the set name to spot over-length names
- Update NetBird: newer agents derive short hashed set names precisely to avoid the 31-char limit
Example fix
// before: set name used as-is, kernel limit not enforced client-side
name := r.ipsetName(network.Set.HashedName())
if _, err := r.ipsetCounter.Increment(name, prefixes); err != nil {
return nil, fmt.Errorf("create or get ipset: %w", err)
}
// after: validate the name before touching the kernel
name := r.ipsetName(network.Set.HashedName())
if len(name) > 31 {
return nil, fmt.Errorf("ipset name %q exceeds kernel limit of 31 chars", name)
}
if _, err := r.ipsetCounter.Increment(name, prefixes); err != nil {
return nil, fmt.Errorf("create or get ipset: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
func ipsetUsable() error {
if _, err := os.Stat("/proc/net/ip_set"); err != nil {
return fmt.Errorf("ipset subsystem unavailable: %w", err)
}
return nil
}
func validSetName(name string) error {
if len(name) > 31 {
return fmt.Errorf("ipset name %q exceeds 31 chars", name)
}
return nil
} Try / catch
Catch at the route-apply layer: on 'apply network -s' failures with set-based sources, log the set name and skip that route rather than aborting the whole network-map application; retry on next sync.
Prevention
- Load ip_set and ip_set_hash_net on routed peers
- Keep agent updated so hashed set names stay short
- In containers, allow NETLINK_NETFILTER through seccomp/AppArmor
When it happens
Trigger: pair.Source.IsSet() true and r.ipsetCounter.Increment(name, prefixes) failing: the ipset netlink subsystem is unavailable (ipset module not loaded), the daemon lacks CAP_NET_ADMIN, the hashed set name exceeds the kernel limit, or a previous create left the refcount inconsistent. Only occurs for routes configured with network sets (large routing groups), not plain CIDR pairs.
Common situations: Hosts without the ipset kernel module or ipset tooling (common in minimal containers); management-defined network sets applied to a peer whose kernel lacks ipset; mixed iptables-nft hosts where ipset compatibility is broken; SELinux denying netlink ipset operations.
Related errors
- apply network -d: %w
- error while adding marking rule for %s: %v
- add IP to ipset: %w
- create set %s: %w
- add element to set %s: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/fc7bc8ed950f2b0d.
Report an issue: GitHub.