{"record":{"id":"fc7bc8ed950f2b0d","repo":"netbirdio/netbird","slug":"apply-network-s-w","errorCode":null,"errorMessage":"apply network -s: %w","messagePattern":"apply network -s: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":689,"sourceCode":"\t}\n\n\tmarkValue := nbnet.PreroutingFwmarkMasquerade\n\tif pair.Inverse {\n\t\tmarkValue = nbnet.PreroutingFwmarkMasqueradeReturn\n\t}\n\n\trule := []string{\"-i\", r.wgIface.Name()}\n\tif pair.Inverse {\n\t\trule = []string{\"!\", \"-i\", r.wgIface.Name()}\n\t}\n\n\trule = append(rule,\n\t\t\"-m\", \"conntrack\",\n\t\t\"--ctstate\", \"NEW\",\n\t)\n\tsourceExp, err := r.applyNetwork(\"-s\", pair.Source, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"apply network -s: %w\", err)\n\t}\n\tdestExp, err := r.applyNetwork(\"-d\", pair.Destination, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"apply network -d: %w\", err)\n\t}\n\n\trule = append(rule, sourceExp...)\n\trule = append(rule, destExp...)\n\trule = append(rule,\n\t\t\"-j\", \"MARK\", \"--set-mark\", fmt.Sprintf(\"%#x\", markValue),\n\t)\n\n\t// Ensure nat rules come first, so the mark can be overwritten.\n\t// Currently overwritten by the dst-type LOCAL rules for redirected traffic.\n\tif err := r.iptablesClient.Insert(tableMangle, chainRTPRE, 1, rule...); err != nil {\n\t\t// TODO: rollback ipset counter\n\t\treturn fmt.Errorf(\"error while adding marking rule for %s: %v\", pair.Destination, err)\n\t}","sourceCodeStart":671,"sourceCodeEnd":707,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L671-L707","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: set name used as-is, kernel limit not enforced client-side\nname := r.ipsetName(network.Set.HashedName())\nif _, err := r.ipsetCounter.Increment(name, prefixes); err != nil {\n    return nil, fmt.Errorf(\"create or get ipset: %w\", err)\n}\n\n// after: validate the name before touching the kernel\nname := r.ipsetName(network.Set.HashedName())\nif len(name) > 31 {\n    return nil, fmt.Errorf(\"ipset name %q exceeds kernel limit of 31 chars\", name)\n}\nif _, err := r.ipsetCounter.Increment(name, prefixes); err != nil {\n    return nil, fmt.Errorf(\"create or get ipset: %w\", err)\n}","handlingStrategy":"validation","validationCode":"func ipsetUsable() error {\n    if _, err := os.Stat(\"/proc/net/ip_set\"); err != nil {\n        return fmt.Errorf(\"ipset subsystem unavailable: %w\", err)\n    }\n    return nil\n}\n\nfunc validSetName(name string) error {\n    if len(name) > 31 {\n        return fmt.Errorf(\"ipset name %q exceeds 31 chars\", name)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["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"],"tags":["network","linux","ipset","iptables","routing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}