{"record":{"id":"5150e75301caae8e","repo":"netbirdio/netbird","slug":"remove-endpoint-address-w","errorCode":null,"errorMessage":"remove endpoint address: %w","messagePattern":"remove endpoint address: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/configurer/usp.go","lineNumber":187,"sourceCode":"\t\tPeers: []wgtypes.PeerConfig{peer},\n\t}\n\tif ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {\n\t\treturn fmt.Errorf(\"failed to remove peer: %s\", ipcErr)\n\t}\n\n\t// Build the peer config\n\tpeer = wgtypes.PeerConfig{\n\t\tPublicKey:         peerKeyParsed,\n\t\tReplaceAllowedIPs: true,\n\t\tAllowedIPs:        allowedIPs,\n\t}\n\n\tconfig = wgtypes.Config{\n\t\tPeers: []wgtypes.PeerConfig{peer},\n\t}\n\n\tif err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {\n\t\treturn fmt.Errorf(\"remove endpoint address: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (c *WGUSPConfigurer) RemovePeer(peerKey string) error {\n\tpeerKeyParsed, err := wgtypes.ParseKey(peerKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpeer := wgtypes.PeerConfig{\n\t\tPublicKey: peerKeyParsed,\n\t\tRemove:    true,\n\t}\n\n\tconfig := wgtypes.Config{\n\t\tPeers: []wgtypes.PeerConfig{peer},","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/configurer/usp.go#L169-L205","documentation":"The second phase of WGUSPConfigurer.RemoveEndpointAddress failed: after removing the peer, re-adding it with its original allowed IPs and no endpoint via IpcSet returned an error. The two-phase remove/re-add is not atomic, so a failure here leaves the peer absent from the device. Causes include the device closing between the two IpcSet calls or an allowed_ip line the UAPI parser rejects.","triggerScenarios":"Device Closed between the removal and re-add IpcSet calls; an allowed IP preserved from the dump that the parser now rejects; concurrent IpcSet from another goroutine invalidating state mid-sequence.","commonSituations":"Shutdown racing endpoint cleanup, leaving the peer deleted; reconnect flow rebuilding the device during the operation; duplicated allowed IPs or malformed CIDRs in the original dump.","solutions":["On failure, re-add the peer with the saved allowedIPs to restore state, or re-run RemoveEndpointAddress","Serialize configurer mutations so IpcSet sequences cannot interleave","Perform endpoint cleanup before device Close in the shutdown order","Log the saved allowedIPs with the error so recovery input is available"],"exampleFix":"// before: fail and leave the peer deleted\nif err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {\n\treturn fmt.Errorf(\"remove endpoint address: %w\", err)\n}\n\n// after: attempt one recovery re-add, then report\nif err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {\n\trestore := wgtypes.Config{Peers: []wgtypes.PeerConfig{{PublicKey: peerKeyParsed, ReplaceAllowedIPs: true, AllowedIPs: allowedIPs}}}\n\tif rErr := c.device.IpcSet(toWgUserspaceString(restore)); rErr != nil {\n\t\treturn fmt.Errorf(\"remove endpoint address: %w (restore failed: %v)\", err, rErr)\n\t}\n\treturn fmt.Errorf(\"remove endpoint address: %w\", err)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := uspCfg.RemoveEndpointAddress(peerKey)\nif err != nil && strings.Contains(err.Error(), \"remove endpoint address\") {\n\t// second phase failed and the peer is now absent: recover by re-running,\n\t// or re-adding the peer with its saved allowed IPs\n\tretryErr := uspCfg.RemoveEndpointAddress(peerKey)\n\tif retryErr != nil && strings.Contains(retryErr.Error(), \"not found\") {\n\t\tretryErr = nil // peer gone: endpoint already cleared by side effect\n\t}\n\terr = retryErr\n}\nreturn err","preventionTips":["Keep the saved allowedIPs available so a failed re-add can be recovered","Prevent device Close from interleaving with the two-phase remove/re-add","Serialize configurer mutations per peer with a mutex","Consider clearing the endpoint via a single IpcSet (endpoint=0.0.0.0:0 style) once supported, avoiding two-phase non-atomicity"],"tags":["wireguard-go","uapi","atomicity","recovery","userspace"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}