netbirdio/netbird · error
update local IPs: %w
Error message
update local IPs: %w
What it means
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.
Source
Thrown at client/firewall/uspfilter/filter.go:323
routeRulesMap: make(map[nbid.RuleID]*RouteRule),
dnatMappings: make(map[netip.Addr]netip.Addr),
portDNATRules: []portDNATRule{},
netstackServices: make(map[serviceKey]struct{}),
mtu: mtu,
}
m.routingEnabled.Store(false)
if !disableMSSClamping {
m.mssClampEnabled = true
if mtu > ipv4TCPHeaderMinSize {
m.mssClampValueIPv4 = mtu - ipv4TCPHeaderMinSize
}
if mtu > ipv6TCPHeaderMinSize {
m.mssClampValueIPv6 = mtu - ipv6TCPHeaderMinSize
}
}
if err := m.localipmanager.UpdateLocalIPs(iface); err != nil {
return nil, fmt.Errorf("update local IPs: %w", err)
}
m.fragments = newFragmentTracker(m.logger)
if disableConntrack {
log.Info("conntrack is disabled")
} else {
m.udpTracker = conntrack.NewUDPTracker(conntrack.DefaultUDPTimeout, m.logger, flowLogger)
m.icmpTracker = conntrack.NewICMPTracker(conntrack.DefaultICMPTimeout, m.logger, flowLogger)
m.tcpTracker = conntrack.NewTCPTracker(conntrack.DefaultTCPTimeout, m.logger, flowLogger)
}
if m.netstack && m.localForwarding {
if err := m.initForwarder(); err != nil {
log.Errorf("failed to initialize forwarder: %v", err)
}
}
if err := iface.SetFilter(m); err != nil {
m.fragments.Close()
return nil, fmt.Errorf("set filter: %w", err)View on GitHub (pinned to 93e97f4bf1)
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
Example fix
// before
if err := m.localipmanager.UpdateLocalIPs(iface); err != nil {
return nil, fmt.Errorf("update local IPs: %w", err)
}
// after - fail with intent when the interface snapshot cannot be trusted
if iface == nil || !iface.Address().IP.IsValid() {
return nil, fmt.Errorf("iface address not ready for local IP snapshot")
}
if err := m.localipmanager.UpdateLocalIPs(iface); err != nil {
return nil, fmt.Errorf("update local IPs: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
// construct the firewall manager only with a ready interface
if wgIface == nil || !wgIface.Address().IP.IsValid() {
return nil, fmt.Errorf("cannot create firewall manager: interface address not ready")
}
fw, err := uspfilter.Create(wgIface, ...) Type guard
func ifaceReadyForUspfilter(i common.IFaceMapper) bool {
return i != nil && i.Address() != nil && i.Address().IP.IsValid()
} Try / catch
fw, err := uspfilter.Create(...)
if err != nil {
if strings.Contains(err.Error(), "update local IPs") {
// interface snapshot failed; retry once after bring-up settles
time.Sleep(settleDelay)
fw, err = uspfilter.Create(...)
}
if err != nil {
return fmt.Errorf("firewall init: %w", err)
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- allow netbird v4 interface traffic: %w
- allow netbird v6 interface traffic: %w
- set filter: %w
- block wg v4 net: %w
- block wg v6 net: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/bacef6df989d4543.
Report an issue: GitHub.