{"record":{"id":"c8addc8a0556ceb8","repo":"netbirdio/netbird","slug":"failed-to-parse-endpoint-address-w","errorCode":null,"errorMessage":"failed to parse endpoint address: %w","messagePattern":"failed to parse endpoint address: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/configurer/usp.go","lineNumber":124,"sourceCode":"\t\t// don't replace allowed ips, wg will handle duplicated peer IP\n\t\tAllowedIPs:                  prefixesToIPNets(allowedIps),\n\t\tPersistentKeepaliveInterval: &keepAlive,\n\t\tPresharedKey:                preSharedKey,\n\t\tEndpoint:                    endpoint,\n\t}\n\n\tconfig := wgtypes.Config{\n\t\tPeers: []wgtypes.PeerConfig{peer},\n\t}\n\n\tif ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {\n\t\treturn ipcErr\n\t}\n\n\tif endpoint != nil {\n\t\taddr, err := netip.ParseAddr(endpoint.IP.String())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse endpoint address: %w\", err)\n\t\t}\n\t\taddrPort := netip.AddrPortFrom(addr.Unmap(), uint16(endpoint.Port))\n\t\tc.activityRecorder.UpsertAddress(peerKey, addrPort)\n\t}\n\treturn nil\n}\n\nfunc (c *WGUSPConfigurer) RemoveEndpointAddress(peerKey string) error {\n\tpeerKeyParsed, err := wgtypes.ParseKey(peerKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse peer key: %w\", err)\n\t}\n\n\tipcStr, err := c.device.IpcGet()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get IPC config: %w\", err)\n\t}\n","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/configurer/usp.go#L106-L142","documentation":"WGUSPConfigurer.UpdatePeer applied the peer config to the userspace device, then failed to parse the endpoint address for the activity recorder via netip.ParseAddr(endpoint.IP.String()). When endpoint is non-nil but endpoint.IP is nil, IP.String() returns the literal '<nil>', which netip refuses to parse. Note the WireGuard config itself was already applied via IpcSet, so the error fires after the state change succeeded.","triggerScenarios":"endpoint *net.UDPAddr constructed with a nil IP (zero-value struct or port-only address); an endpoint.IP of abnormal length that netip.ParseAddr rejects; hostname resolution upstream producing an address-less UDPAddr.","commonSituations":"Connection manager passing a UDPAddr built from a config field that never got filled; relay/ICE code creating UDPAddr{Port: n} before the address is known; marshaling round-trips losing the IP.","solutions":["Guard with endpoint != nil && endpoint.IP != nil before parsing","Build the value with netip.AddrFromSlice(endpoint.IP) and skip on !ok instead of round-tripping through String()","Fix the upstream producer to always set IP and Port together on the UDPAddr","Treat this as recorder-only bookkeeping: log and continue instead of failing UpdatePeer after a successful IpcSet"],"exampleFix":"// before\naddr, err := netip.ParseAddr(endpoint.IP.String())\nif err != nil {\n\treturn fmt.Errorf(\"failed to parse endpoint address: %w\", err)\n}\n\n// after\nif addr, ok := netip.AddrFromSlice(endpoint.IP); ok {\n\taddrPort := netip.AddrPortFrom(addr.Unmap(), uint16(endpoint.Port))\n\tc.activityRecorder.UpsertAddress(peerKey, addrPort)\n} else {\n\tlog.Warnf(\"skipping activity record for peer %s: invalid endpoint IP\", peerKey)\n}","handlingStrategy":"validation","validationCode":"// validate the endpoint before UpdatePeer reaches the recorder step\nfunc validEndpoint(ep *net.UDPAddr) bool {\n\treturn ep != nil && ep.IP != nil && ep.Port > 0 && ep.Port <= 65535\n}\n\nif !validEndpoint(endpoint) {\n\tendpoint = nil // UpdatePeer accepts a nil endpoint\n}","typeGuard":"func hasParsableEndpoint(ep *net.UDPAddr) bool {\n\tif ep == nil || ep.IP == nil {\n\t\treturn false\n\t}\n\t_, ok := netip.AddrFromSlice(ep.IP)\n\treturn ok\n}","tryCatchPattern":"if err := uspCfg.UpdatePeer(key, prefixes, keepalive, endpoint, psk); err != nil {\n\tif strings.Contains(err.Error(), \"failed to parse endpoint address\") {\n\t\t// config already applied; only the activity recorder failed: retry with nil endpoint or log\n\t\tlog.Warnf(\"peer applied but endpoint unparsable: %v\", err)\n\t\treturn nil\n\t}\n\treturn err\n}","preventionTips":["Never build net.UDPAddr without setting both IP and Port","Convert addresses with netip.AddrFromSlice instead of String()/ParseAddr round-trips","Validate endpoints at the boundary where ICE/relay results are converted","Remember IpcSet already succeeded when this error fires; do not blindly retry the whole update"],"tags":["wireguard","userspace","endpoint","netip","parsing","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}