netbirdio/netbird · error · firewall.ErrIPv6NotInitialized
add peer filtering for %s: %w
Error message
add peer filtering for %s: %w
What it means
AddPeerFiltering was called with an IPv6 peer IP (ip.To4() == nil) while the manager has no v6 half: m.ipv6Client is nil because wgIface.Address().HasIPv6() was false when Create ran. It wraps the sentinel firewall.ErrIPv6NotInitialized (client/firewall/manager/firewall.go:17), so the mismatch is programmatically detectable with errors.Is. The check fails fast rather than silently installing a v6 address into the v4 chain or ipset.
Source
Thrown at client/firewall/iptables/manager_linux.go:198
//
// Comment will be ignored because some system this feature is not supported
func (m *Manager) AddPeerFiltering(
id []byte,
ip net.IP,
proto firewall.Protocol,
sPort *firewall.Port,
dPort *firewall.Port,
action firewall.Action,
ipsetName string,
) ([]firewall.Rule, error) {
m.mutex.Lock()
defer m.mutex.Unlock()
if ip.To4() != nil {
return m.aclMgr.AddPeerFiltering(id, ip, proto, sPort, dPort, action, ipsetName)
}
if !m.hasIPv6() {
return nil, fmt.Errorf("add peer filtering for %s: %w", ip, firewall.ErrIPv6NotInitialized)
}
return m.aclMgr6.AddPeerFiltering(id, ip, proto, sPort, dPort, action, ipsetName)
}
func (m *Manager) AddRouteFiltering(
id []byte,
sources []netip.Prefix,
destination firewall.Network,
proto firewall.Protocol,
sPort, dPort *firewall.Port,
action firewall.Action,
) (firewall.Rule, error) {
m.mutex.Lock()
defer m.mutex.Unlock()
if isIPv6RouteRule(sources, destination) {
if !m.hasIPv6() {
return nil, fmt.Errorf("add route filtering: %w", firewall.ErrIPv6NotInitialized)View on GitHub (pinned to 93e97f4bf1)
Solutions
- Give the peer an IPv6 address (enable the v6 range in the management network) and restart/reconnect so Create builds the v6 half
- If v6 is unsupported locally, stop distributing v6 ACLs/routes to this peer from management
- In custom callers, skip v6 peers when the interface has no v6 - the engine already does this at client/internal/engine.go:1842
Example fix
// before
rules, err := mgr.AddPeerFiltering(id, peerIP, proto, sPort, dPort, action, ipset)
if err != nil {
return err // v6 peer on v4-only manager aborts the whole ACL apply
}
// after
if peerIP.To4() == nil && !wgIface.Address().HasIPv6() {
log.Debugf("skipping v6 peer %s: no v6 overlay", peerIP)
continue
}
rules, err := mgr.AddPeerFiltering(id, peerIP, proto, sPort, dPort, action, ipset) Defensive patterns
Strategy: validation
Validate before calling
// skip v6 peer rules before touching the firewall manager
func canFilterPeer(mgrFacingV6 bool, peerIP net.IP) bool {
if peerIP.To4() != nil {
return true
}
return mgrFacingV6 // mgrFacingV6 == wgIface.Address().HasIPv6() at Create time
} Type guard
func isFilterableIP(ip net.IP, ifaceHasV6 bool) bool {
return ip.To4() != nil || ifaceHasV6
} Try / catch
rules, err := mgr.AddPeerFiltering(id, ip, proto, sPort, dPort, action, ipsetName)
if err != nil {
if errors.Is(err, firewall.ErrIPv6NotInitialized) {
log.Debugf("skipping v6 peer %s: no v6 firewall", ip)
continue
}
return err
} Prevention
- Gate every v6 submission on wgIface.Address().HasIPv6(), the same check Create uses
- Match the sentinel with errors.Is rather than string-matching the message
- Keep management-side v6 ACL distribution scoped to peers that actually hold v6 addresses
When it happens
Trigger: Passing a 16-byte net.IP (a v6 peer address from the network map) to AddPeerFiltering on a manager constructed while the local overlay address had no IPv6 part.
Common situations: Management network has an IPv6 range so peers carry v6 addresses, but this peer was assigned a v4-only address; the peer connected before v6 was enabled and was not restarted; the kernel or interface had no v6 at startup so the WgAddr lacks the v6 component.
Related errors
- reset v6 acl manager: %w
- allow netbird v6 interface traffic: %w
- add IP to ipset: %w
- failed to check rule: %w
- rule already exists
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/a158e142529d4b56.
Report an issue: GitHub.