{"record":{"id":"8d3d366f3ddeda7c","repo":"netbirdio/netbird","slug":"source-w","errorCode":null,"errorMessage":"source: %w","messagePattern":"source: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/nftables/router_linux.go","lineNumber":2121,"sourceCode":"\t}\n\tif err := r.conn.Flush(); err != nil {\n\t\treturn fmt.Errorf(\"flush delete output DNAT rule: %w\", err)\n\t}\n\tdelete(r.rules, ruleID)\n\n\treturn nil\n}\n\n// applyNetwork generates nftables expressions for networks (CIDR) or sets\nfunc (r *router) applyNetwork(\n\tnetwork firewall.Network,\n\tsetPrefixes []netip.Prefix,\n\tisSource bool,\n) ([]expr.Any, error) {\n\tif network.IsSet() {\n\t\texprs, err := r.getIpSet(network.Set, setPrefixes, isSource)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"source: %w\", err)\n\t\t}\n\t\treturn exprs, nil\n\t}\n\n\tif network.IsPrefix() {\n\t\treturn r.applyPrefix(network.Prefix, isSource), nil\n\t}\n\n\treturn nil, nil\n}\n\n// applyPrefix generates nftables expressions for a CIDR prefix\nfunc (r *router) applyPrefix(prefix netip.Prefix, isSource bool) []expr.Any {\n\t// dst offset by default\n\toffset := r.af.dstAddrOffset\n\tif isSource {\n\t\t// src offset\n\t\toffset = r.af.srcAddrOffset","sourceCodeStart":2103,"sourceCodeEnd":2139,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/nftables/router_linux.go#L2103-L2139","documentation":"Returned by router.applyNetwork (client/firewall/nftables/router_linux.go:2121) when a Network-Set source cannot be turned into nftables expressions. It wraps getIpSet, which increments a refcounted nft Set (ipsetCounter.Increment) and can fail while creating the set ('create or get ipset') or building the lookup expressions - e.g. set with prefixes of the wrong address family for the table, overlapping/unmergeable intervals, oversized element batches, or a netlink failure on AddSet/Flush. The terse 'source:' prefix marks this as the source-side leg; the same helper is reused for destinations.","triggerScenarios":"A routing/ACL policy whose network Set contains prefixes that do not match the router's address family (v6 prefixes in the IPv4 table); two different Sets hashed to the same nft name with different contents; a Set so large the element batch exceeds netlink limits; Set created previously with incompatible flags (Interval/KeyType) by an older agent version.","commonSituations":"Management sends a mixed-family distribution group; duplicate network names colliding in HashedName; upgrading the agent while old nft sets persist from the previous version; concurrent route updates racing on the same set name.","solutions":["Filter the Set's prefixes by address family before calling AddRouteRule so only prefixes matching r.af reach the table","Ensure overlapping prefixes are merged (firewall.MergeIPRanges is applied in createIpSet) and that the same HashedName always maps to identical prefix contents","If a stale set with incompatible flags exists, recreate the manager (Create) which rebuilds the work table, then re-add routes","Batch-check element counts against maxPrefixesSet limits and split very large sets"],"exampleFix":"// before\nexprs, err := r.getIpSet(network.Set, setPrefixes, isSource)\nif err != nil {\n    return nil, fmt.Errorf(\"source: %w\", err)\n}\n// after - drop prefixes that do not belong to this table's family\ncompatible := filterPrefixesForFamily(setPrefixes, r.af.tableFamily == nftables.TableFamilyIPv4)\nexprs, err := r.getIpSet(network.Set, compatible, isSource)\nif err != nil {\n    return nil, fmt.Errorf(\"source: %w\", err)\n}","handlingStrategy":"validation","validationCode":"// Keep only prefixes that match the router's family before adding a route\nwantV4 := tableFamily == nftables.TableFamilyIPv4\ncompatible := make([]netip.Prefix, 0, len(setPrefixes))\nfor _, p := range setPrefixes {\n    if p.Addr().Is4() == wantV4 {\n        compatible = append(compatible, p.Masked())\n    }\n}\nif len(compatible) == 0 {\n    return fmt.Errorf(\"network set %s has no %s prefixes\", set.Name(), family)\n}","typeGuard":"func prefixesMatchFamily(ps []netip.Prefix, v4 bool) bool {\n    for _, p := range ps {\n        if p.Addr().Is4() != v4 {\n            return false\n        }\n    }\n    return len(ps) > 0\n}","tryCatchPattern":"if _, err := router.AddRouteRule(net, sources, ...); err != nil {\n    if strings.Contains(err.Error(), \"source:\") || strings.Contains(err.Error(), \"ipset\") {\n        log.Warnf(\"network set %s unusable on this family, skipping route\", net.ID)\n        continue\n    }\n    return err\n}","preventionTips":["Mask and merge overlapping prefixes before submitting sets","Ensure a given set name always carries identical prefix contents across updates","Split sets that exceed the element batch limit instead of relying on runtime failure"],"tags":["nftables","ipset","routing","linux"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}