netbirdio/netbird · error
remove endpoint address: %w
Error message
remove endpoint address: %w
What it means
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.
Source
Thrown at client/iface/configurer/usp.go:187
Peers: []wgtypes.PeerConfig{peer},
}
if ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {
return fmt.Errorf("failed to remove peer: %s", ipcErr)
}
// Build the peer config
peer = wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
ReplaceAllowedIPs: true,
AllowedIPs: allowedIPs,
}
config = wgtypes.Config{
Peers: []wgtypes.PeerConfig{peer},
}
if err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {
return fmt.Errorf("remove endpoint address: %w", err)
}
return nil
}
func (c *WGUSPConfigurer) RemovePeer(peerKey string) error {
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
if err != nil {
return err
}
peer := wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
Remove: true,
}
config := wgtypes.Config{
Peers: []wgtypes.PeerConfig{peer},View on GitHub (pinned to 93e97f4bf1)
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
Example fix
// before: fail and leave the peer deleted
if err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {
return fmt.Errorf("remove endpoint address: %w", err)
}
// after: attempt one recovery re-add, then report
if err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {
restore := wgtypes.Config{Peers: []wgtypes.PeerConfig{{PublicKey: peerKeyParsed, ReplaceAllowedIPs: true, AllowedIPs: allowedIPs}}}
if rErr := c.device.IpcSet(toWgUserspaceString(restore)); rErr != nil {
return fmt.Errorf("remove endpoint address: %w (restore failed: %v)", err, rErr)
}
return fmt.Errorf("remove endpoint address: %w", err)
} Defensive patterns
Strategy: retry
Try / catch
err := uspCfg.RemoveEndpointAddress(peerKey)
if err != nil && strings.Contains(err.Error(), "remove endpoint address") {
// second phase failed and the peer is now absent: recover by re-running,
// or re-adding the peer with its saved allowed IPs
retryErr := uspCfg.RemoveEndpointAddress(peerKey)
if retryErr != nil && strings.Contains(retryErr.Error(), "not found") {
retryErr = nil // peer gone: endpoint already cleared by side effect
}
err = retryErr
}
return err Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/5150e75301caae8e.
Report an issue: GitHub.