netbirdio/netbird · error
error re-adding peer %s to interface %s with allowed IPs %v:
Error message
error re-adding peer %s to interface %s with allowed IPs %v: %w
What it means
The second half of RemoveEndpointAddress (re-adding the peer with its original allowed IPs but no endpoint) failed after the peer had already been removed. Unlike the remove step, this error leaves the device in a degraded state: the peer is gone from WireGuard, so its routes/allowed IPs no longer match until the operation succeeds. Recovery requires re-adding the peer, either by retrying or by triggering a full peer resync from the network map.
Source
Thrown at client/iface/configurer/kernel_unix.go:118
removePeerCfg := wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
Remove: true,
}
if err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{removePeerCfg}}); err != nil {
return fmt.Errorf(`error removing peer %s from interface %s: %w`, peerKey, c.deviceName, err)
}
//Re-add the peer without the endpoint but same AllowedIPs
reAddPeerCfg := wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
AllowedIPs: existingPeer.AllowedIPs,
ReplaceAllowedIPs: true,
}
if err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); err != nil {
return fmt.Errorf(
`error re-adding peer %s to interface %s with allowed IPs %v: %w`,
peerKey, c.deviceName, existingPeer.AllowedIPs, err,
)
}
return nil
}
func (c *KernelConfigurer) RemovePeer(peerKey string) error {
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
if err != nil {
return err
}
peer := wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
Remove: true,
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Retry the re-add immediately with the same peer config; the inputs (existingPeer.AllowedIPs) are already captured
- If retry keeps failing, trigger a full peer resync (re-apply all peers from the network map) to restore the device
- Alert on this specific error: it is the one endpoint-removal failure that actually degrades connectivity
- Check device existence and privileges before retrying so you do not loop on a permanent cause
Example fix
// before
if err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); err != nil {
return fmt.Errorf(`error re-adding peer %s ...`, peerKey, c.deviceName, existingPeer.AllowedIPs, err)
}
// after
if err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); err != nil {
if retryErr := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); retryErr != nil {
return fmt.Errorf(`error re-adding peer %s ...: %w (retry: %v)`, peerKey, c.deviceName, existingPeer.AllowedIPs, err, retryErr)
}
} Defensive patterns
Strategy: retry
Validate before calling
// before the whole remove/re-add, capture the desired end state
existing, err := getPeer(deviceName, peerKey)
if err != nil { return err }
desired := wgtypes.PeerConfig{
PublicKey: existing.PublicKey,
AllowedIPs: existing.AllowedIPs,
ReplaceAllowedIPs: true,
} // on any later failure, re-apply this config to restore the peer Type guard
func deviceCanBeConfigured(name string) bool {
client, err := wgctrl.New()
if err != nil {
return false
}
defer client.Close()
_, err = client.Device(name)
return err == nil
} Try / catch
if err := configurer.RemoveEndpointAddress(peerKey); err != nil {
if strings.Contains(err.Error(), "re-adding peer") {
// peer is currently absent: re-apply desired config immediately
if retryErr := reapplyPeer(desired); retryErr != nil {
return fmt.Errorf("peer %s left off-device: %w", peerKey, err)
}
return nil
}
return err
} Prevention
- Treat 'error re-adding peer' as a connectivity-loss event: alert and self-heal by re-applying the peer config
- Keep the captured allowed IPs from getPeer available for recovery until the operation succeeds
- Retry bounded (2-3 attempts) then escalate to a full peer resync from the network map
- Avoid interleaving endpoint removal with engine restarts
When it happens
Trigger: Device removed or permissions lost between the remove and re-add configures; an allowed-IP list that the kernel now rejects (e.g. family/mask corruption) even though it was read straight from getPeer; netlink failure under memory pressure or concurrent updates.
Common situations: Teardown racing endpoint cleanup during shutdown or reconnection; long-lived agents that accumulated unusual allowed-IP sets; hosts with flaky uapi/netlink transports.
Related errors
- received error "%w" while updating peer on interface %s with
- get peer: %w
- error removing peer %s from interface %s: %w
- received error "%w" while removing peer %s from interface %s
- received error "%w" while configuring interface %s with port
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/d4e54e62b64fff21.
Report an issue: GitHub.