{"record":{"id":"2e20423e23be5d43","repo":"netbirdio/netbird","slug":"add-ipv6-protocol-address-s","errorCode":null,"errorMessage":"add IPv6 protocol address: %s","messagePattern":"add IPv6 protocol address: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/uspfilter/forwarder/forwarder.go","lineNumber":108,"sourceCode":"\t\t\tAddress:   tcpip.AddrFrom4(iface.Address().IP.As4()),\n\t\t\tPrefixLen: iface.Address().Network.Bits(),\n\t\t},\n\t}\n\n\tif err := s.AddProtocolAddress(nicID, protoAddr, stack.AddressProperties{}); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to add protocol address: %s\", err)\n\t}\n\n\tif v6 := iface.Address().IPv6; v6.IsValid() {\n\t\tv6Addr := tcpip.ProtocolAddress{\n\t\t\tProtocol: ipv6.ProtocolNumber,\n\t\t\tAddressWithPrefix: tcpip.AddressWithPrefix{\n\t\t\t\tAddress:   tcpip.AddrFrom16(v6.As16()),\n\t\t\t\tPrefixLen: iface.Address().IPv6Net.Bits(),\n\t\t\t},\n\t\t}\n\t\tif err := s.AddProtocolAddress(nicID, v6Addr, stack.AddressProperties{}); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"add IPv6 protocol address: %s\", err)\n\t\t}\n\t}\n\n\tdefaultSubnet, err := tcpip.NewSubnet(\n\t\ttcpip.AddrFrom4([4]byte{0, 0, 0, 0}),\n\t\ttcpip.MaskFromBytes([]byte{0, 0, 0, 0}),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating default subnet: %w\", err)\n\t}\n\n\tdefaultSubnetV6, err := tcpip.NewSubnet(\n\t\ttcpip.AddrFrom16([16]byte{}),\n\t\ttcpip.MaskFromBytes(make([]byte, 16)),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating default v6 subnet: %w\", err)\n\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/uspfilter/forwarder/forwarder.go#L90-L126","documentation":"Returned by forwarder.New when the gVisor netstack rejects the IPv6 address assignment for the NIC (stack.AddProtocolAddress). gVisor returns tcpip.ErrDuplicateLocalAddress when the address was already registered on that NIC, or an invalid-prefix error when PrefixLen exceeds the protocol's bit width. At this point in the constructor the IPv4 address has already been added and the NIC created, so the whole userspace forwarder fails to come up.","triggerScenarios":"Calling forwarder.New with an interface whose Address().IPv6 is valid but whose IPv6Net prefix bits are invalid (>128 or negative from a misparsed CIDR), or calling New twice against state where the same v6 address already exists; also a teardown race where the NIC was removed between CreateNIC and this call.","commonSituations":"IPv6 overlay enabled in NetBird while the interface address/prefix were populated from a malformed config or a management network range that is not a real /prefix; concurrent interface re-creation (BindUpdate/engine restart) racing the forwarder constructor; gVisor version change tightening AddProtocolAddress validation.","solutions":["Check the IPv6 address and prefix reported by iface.Address() before constructing the Forwarder: IPv6.IsValid() must be true and IPv6Net.Bits() must be 0..128","Ensure only one Forwarder instance per stack/NIC lifecycle; tear down the old forwarder (cancel + stack cleanup) before creating a new one","If the overlay was configured without IPv6, verify the address mapper is not returning a stale v6 address after a reconfiguration","Upgrade gvisor.dev/gvisor if the wrapped error text points at an AddressProperties validation added in a newer version"],"exampleFix":"// before\nif v6 := iface.Address().IPv6; v6.IsValid() {\n    // ... AddProtocolAddress\n}\n\n// after\nif v6 := iface.Address().IPv6; v6.IsValid() {\n    if bits := iface.Address().IPv6Net.Bits(); bits < 0 || bits > 128 {\n        return nil, fmt.Errorf(\"invalid IPv6 prefix length %d\", bits)\n    }\n    // ... AddProtocolAddress\n}","handlingStrategy":"validation","validationCode":"// before constructing the forwarder\na := iface.Address()\nif a.IPv6.IsValid() {\n    if bits := a.IPv6Net.Bits(); bits < 0 || bits > 128 {\n        return fmt.Errorf(\"invalid IPv6 prefix %s\", a.IPv6Net)\n    }\n}\nf, err := forwarder.New(iface, logger, flowLogger, netstack, mtu)","typeGuard":"func validV6Assignment(a wgaddr.Address) bool {\n    v6 := a.IPv6\n    if !v6.IsValid() {\n        return true // v4-only is fine; the v6 block is skipped\n    }\n    bits := a.IPv6Net.Bits()\n    return bits >= 0 && bits <= 128 && v6.Is6()\n}","tryCatchPattern":"if _, err := forwarder.New(...); err != nil {\n    if strings.Contains(err.Error(), \"add IPv6 protocol address\") {\n        // re-check address state, recreate interface, retry once\n    }\n    return err\n}","preventionTips":["Validate interface address/prefix pairs before every forwarder construction","Tear down and join the previous forwarder before creating a new one","Log iface.Address() contents at debug when bring-up fails to capture the exact v6 values"],"tags":["go","netbird","gvisor","netstack","ipv6","firewall"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}