{"record":{"id":"bacef6df989d4543","repo":"netbirdio/netbird","slug":"update-local-ips-w","errorCode":null,"errorMessage":"update local IPs: %w","messagePattern":"update local IPs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/uspfilter/filter.go","lineNumber":323,"sourceCode":"\t\trouteRulesMap:       make(map[nbid.RuleID]*RouteRule),\n\t\tdnatMappings:        make(map[netip.Addr]netip.Addr),\n\t\tportDNATRules:       []portDNATRule{},\n\t\tnetstackServices:    make(map[serviceKey]struct{}),\n\t\tmtu:                 mtu,\n\t}\n\tm.routingEnabled.Store(false)\n\n\tif !disableMSSClamping {\n\t\tm.mssClampEnabled = true\n\t\tif mtu > ipv4TCPHeaderMinSize {\n\t\t\tm.mssClampValueIPv4 = mtu - ipv4TCPHeaderMinSize\n\t\t}\n\t\tif mtu > ipv6TCPHeaderMinSize {\n\t\t\tm.mssClampValueIPv6 = mtu - ipv6TCPHeaderMinSize\n\t\t}\n\t}\n\tif err := m.localipmanager.UpdateLocalIPs(iface); err != nil {\n\t\treturn nil, fmt.Errorf(\"update local IPs: %w\", err)\n\t}\n\tm.fragments = newFragmentTracker(m.logger)\n\n\tif disableConntrack {\n\t\tlog.Info(\"conntrack is disabled\")\n\t} else {\n\t\tm.udpTracker = conntrack.NewUDPTracker(conntrack.DefaultUDPTimeout, m.logger, flowLogger)\n\t\tm.icmpTracker = conntrack.NewICMPTracker(conntrack.DefaultICMPTimeout, m.logger, flowLogger)\n\t\tm.tcpTracker = conntrack.NewTCPTracker(conntrack.DefaultTCPTimeout, m.logger, flowLogger)\n\t}\n\tif m.netstack && m.localForwarding {\n\t\tif err := m.initForwarder(); err != nil {\n\t\t\tlog.Errorf(\"failed to initialize forwarder: %v\", err)\n\t\t}\n\t}\n\tif err := iface.SetFilter(m); err != nil {\n\t\tm.fragments.Close()\n\t\treturn nil, fmt.Errorf(\"set filter: %w\", err)","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/uspfilter/filter.go#L305-L341","documentation":"Returned by the uspfilter Manager constructor (client/firewall/uspfilter/filter.go:323) when m.localipmanager.UpdateLocalIPs(iface) fails. UpdateLocalIPs (localip.go:63) enumerates net.Interfaces() (whose error is only logged) and wraps the whole body in a panic-recover that converts any panic into 'panic: %v' - so this wrapper in practice fires when iface.Address() or the interface walk panics (nil IFaceMapper, unset WGIface address), not on ordinary OS errors.","triggerScenarios":"Creating the uspfilter manager with a nil or half-initialized common.IFaceMapper whose Address() dereferences nil; WGIface created but address not yet assigned (Address().IP zero/invalid) when the firewall manager is constructed; a net.Interface with malformed flags/addresses triggering a panic in processInterface.","commonSituations":"Construction ordering bugs where the firewall manager is built before the overlay interface is up; embedded/wasm netstack paths where the iface wrapper differs; races between interface setup and ACL initialization.","solutions":["Ensure the WireGuard interface exists and has its address assigned before constructing the uspfilter manager; pass a fully initialized IFaceMapper","Guard UpdateLocalIPs against a nil iface and an invalid Address().IP (skip or error early with a clear message)","Log the recovered panic value at error level with a stack so the origin inside processInterface is visible","Add a constructor-time sanity check: if iface == nil || !iface.Address().IP.IsValid() return a descriptive error before calling UpdateLocalIPs"],"exampleFix":"// before\nif err := m.localipmanager.UpdateLocalIPs(iface); err != nil {\n    return nil, fmt.Errorf(\"update local IPs: %w\", err)\n}\n// after - fail with intent when the interface snapshot cannot be trusted\nif iface == nil || !iface.Address().IP.IsValid() {\n    return nil, fmt.Errorf(\"iface address not ready for local IP snapshot\")\n}\nif err := m.localipmanager.UpdateLocalIPs(iface); err != nil {\n    return nil, fmt.Errorf(\"update local IPs: %w\", err)\n}","handlingStrategy":"validation","validationCode":"// construct the firewall manager only with a ready interface\nif wgIface == nil || !wgIface.Address().IP.IsValid() {\n    return nil, fmt.Errorf(\"cannot create firewall manager: interface address not ready\")\n}\nfw, err := uspfilter.Create(wgIface, ...)","typeGuard":"func ifaceReadyForUspfilter(i common.IFaceMapper) bool {\n    return i != nil && i.Address() != nil && i.Address().IP.IsValid()\n}","tryCatchPattern":"fw, err := uspfilter.Create(...)\nif err != nil {\n    if strings.Contains(err.Error(), \"update local IPs\") {\n        // interface snapshot failed; retry once after bring-up settles\n        time.Sleep(settleDelay)\n        fw, err = uspfilter.Create(...)\n    }\n    if err != nil {\n        return fmt.Errorf(\"firewall init: %w\", err)\n    }\n}","preventionTips":["Order engine bring-up: interface up and addressed, then firewall manager","Never pass a nil IFaceMapper to the uspfilter constructor","Keep the panic-recover in UpdateLocalIPs, but log the recovered value with a stack to find constructor races"],"tags":["uspfilter","firewall","interface-init","userspace"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}