{"record":{"id":"3907f40030597ed9","repo":"netbirdio/netbird","slug":"failed-to-add-protocol-address-s","errorCode":null,"errorMessage":"failed to add protocol address: %s","messagePattern":"failed to add protocol address: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/uspfilter/forwarder/forwarder.go","lineNumber":96,"sourceCode":"\t\tlogger: logger,\n\t\tdevice: iface.GetWGDevice(),\n\t}\n\tendpoint.mtu.Store(uint32(mtu))\n\n\tif err := s.CreateNIC(nicID, endpoint); err != nil {\n\t\treturn nil, fmt.Errorf(\"create NIC: %v\", err)\n\t}\n\n\tprotoAddr := tcpip.ProtocolAddress{\n\t\tProtocol: ipv4.ProtocolNumber,\n\t\tAddressWithPrefix: tcpip.AddressWithPrefix{\n\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}),","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/uspfilter/forwarder/forwarder.go#L78-L114","documentation":"Returned by forwarder.New (client/firewall/uspfilter/forwarder/forwarder.go:96) when s.AddProtocolAddress on NIC 1 with the overlay's IPv4 address fails. gVisor rejects protocol-address additions for a non-existent NIC, a duplicate address, or an invalid prefix length; since the address comes from iface.Address().IP.As4() with Bits() from the network, a zero/invalid interface address or out-of-range prefix length produces this. The message uses %s on a tcpip error (not wrapped) and duplicates the 'failed to' wording - the underlying error type is lost to callers.","triggerScenarios":"forwarder.New called before the interface address was assigned, so Address().IP is the zero value and/or Network.Bits() is invalid; duplicate AddProtocolAddress after a double init; prefix length > 32 reaching tcpip.","commonSituations":"Routing enabled in a bring-up race before address configuration completes; management delivering a network address whose prefix length the agent did not sanitize; embedded/wasm paths where Address() is populated asynchronously.","solutions":["Require iface.Address().IP.IsValid() and 0 <= Network.Bits() <= 32 (and v6 bits <= 128) before constructing the forwarder","Retry EnableRouting after the interface is configured; construction then receives a valid address","When adding the optional v6 leg, keep the existing IsValid() guard so an absent v6 skips instead of failing","Wrap the error with %w so callers can match tcpip error types"],"exampleFix":"// before\nif err := s.AddProtocolAddress(nicID, protoAddr); err != nil {\n    return nil, fmt.Errorf(\"failed to add protocol address: %s\", err)\n}\n// after - validate inputs, preserve the error chain\naddr := iface.Address()\nif !addr.IP.IsValid() || addr.Network.Bits() > 32 {\n    return nil, fmt.Errorf(\"invalid overlay address %s/%d\", addr.IP, addr.Network.Bits())\n}\nif err := s.AddProtocolAddress(nicID, protoAddr); err != nil {\n    return nil, fmt.Errorf(\"add protocol address %s: %w\", protoAddr.AddressWithPrefix, err)\n}","handlingStrategy":"validation","validationCode":"a := iface.Address()\nif !a.IP.IsValid() || !a.IP.Is4() || a.Network.Bits() > 32 {\n    return fmt.Errorf(\"forwarder needs a valid IPv4 overlay address, got %s/%d\", a.IP, a.Network.Bits())\n}\n_ = fw.EnableRouting()","typeGuard":"func validOverlayAddress(a common.WGAddress) bool {\n    return a.IP.IsValid() && a.IP.Is4() && a.Network.Bits() <= 32 &&\n        (!a.IPv6.IsValid() || a.IPv6Net.Bits() <= 128)\n}","tryCatchPattern":"if err := fw.EnableRouting(); err != nil {\n    msg := err.Error()\n    if strings.Contains(msg, \"protocol address\") {\n        // interface not addressed yet; retry once after bring-up\n        time.Sleep(settleDelay)\n        return fw.EnableRouting()\n    }\n    return err\n}","preventionTips":["Enable routing only after the interface address is assigned and valid","Keep the IPv6 address optional (IsValid guard) so a missing v6 never fails the v4 forwarder","Fix the wrapper to use %w instead of %s so tcpip errors stay inspectable"],"tags":["gvisor","netstack","forwarder","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}