netbirdio/netbird · error
block wg v6 net: %w
Error message
block wg v6 net: %w
What it means
Returned by blockInvalidRouted (client/firewall/uspfilter/filter.go:388) when the same drop rule cannot be installed for the IPv6 overlay prefix (v6Net.IsValid() was true, so the agent attempted the v6 leg). Per the function's contract, a v6 failure leaves the v4 rule installed and the returned slice still contains v4 - callers must persist it so DisableRouting can clean partial state. Failures are input-class: an interface-reported v6 prefix that is present but malformed (wrong bit length, non-canonical), or invalid v6 sources.
Source
Thrown at client/firewall/uspfilter/filter.go:388
)
if err != nil {
return rules, fmt.Errorf("block wg v4 net: %w", err)
}
rules = append(rules, v4Rule)
if v6Net.IsValid() {
log.Debugf("blocking invalid routed traffic for %s", v6Net)
v6Rule, err := m.addRouteFiltering(
nil,
sources,
firewall.Network{Prefix: v6Net},
firewall.ProtocolALL,
nil,
nil,
firewall.ActionDrop,
)
if err != nil {
return rules, fmt.Errorf("block wg v6 net: %w", err)
}
rules = append(rules, v6Rule)
}
// TODO: Block networks that we're a client of
return rules, nil
}
func (m *Manager) determineRouting() error {
var disableUspRouting, forceUserspaceRouter bool
var err error
if val := os.Getenv(EnvDisableUserspaceRouting); val != "" {
disableUspRouting, err = strconv.ParseBool(val)
if err != nil {
log.Warnf("failed to parse %s: %v", EnvDisableUserspaceRouting, err)
}
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Normalize the v6 prefix (Masked(), sane Bits bounds) before calling blockInvalidRouted; skip the v6 leg when normalization deems it unusable
- Treat v6 block failure as non-fatal per the IPv6-soft-feature policy: keep v4 protection, log a warning, and continue routing
- Always persist the returned partial rules slice so DisableRouting cleans whatever was installed
- If v6 is not needed, run the overlay IPv4-only so v6Net.IsValid() is false and the leg is skipped
Example fix
// before
v6Rule, err := m.addRouteFiltering(nil, sources, firewall.Network{Prefix: v6Net}, firewall.ProtocolALL, nil, nil, firewall.ActionDrop)
if err != nil {
return rules, fmt.Errorf("block wg v6 net: %w", err)
}
// after - keep v4 protection, degrade the v6 leg to a warning
v6Rule, err := m.addRouteFiltering(nil, sources, firewall.Network{Prefix: v6Net}, firewall.ProtocolALL, nil, nil, firewall.ActionDrop)
if err != nil {
log.Warnf("skip invalid routed v6 block for %s: %v", v6Net, err)
return rules, nil
}
rules = append(rules, v6Rule) Defensive patterns
Strategy: fallback
Validate before calling
v6 := iface.Address().IPv6Net
if v6.IsValid() && (v6.Bits() < 0 || v6.Bits() > 128 || !v6.Addr().Is6() || v6.Addr().Is4In6()) {
// treat as 'no v6' rather than failing EnableRouting
v6 = netip.Prefix{}
} Type guard
func usableOverlayV6(p netip.Prefix) bool {
return p.IsValid() && p.Addr().Is6() && !p.Addr().Is4In6() && p.Bits() >= 0 && p.Bits() <= 128
} Try / catch
if err := fw.EnableRouting(); err != nil {
if strings.Contains(err.Error(), "block wg v6 net") {
log.Warnf("continuing v4-only routing; v6 default-drop failed: %v", err)
err = nil
}
if err != nil {
return err
}
} Prevention
- Apply Unmap()/Masked() to v6 overlay prefixes when parsing management config
- Never let a v6 leg failure abort v4 routing - IPv6 is a soft feature
- Persist whatever rules were installed so DisableRouting cleans partial state
When it happens
Trigger: Dual-stack overlay where iface.Address().IPv6Net reports a valid-but-unusable prefix (e.g. Bits() > 64 or host bits set non-canonically); v6 sources from the network map that fail validation mid-install.
Common situations: Management pushes an IPv6 range with an unusual prefix length; agent version mismatch in v6 address normalization (Unmap missing, v4-mapped entries in the v6 net); hosts with flapping v6 capability re-enabling the v6 leg mid-session.
Related errors
- add route filtering: %w
- reset v6 router: %w
- block wg v4 net: %w
- block invalid routed: %w
- create IPv6 firewall: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/190b7d01446542e4.
Report an issue: GitHub.