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

  1. Retry the re-add immediately with the same peer config; the inputs (existingPeer.AllowedIPs) are already captured
  2. If retry keeps failing, trigger a full peer resync (re-apply all peers from the network map) to restore the device
  3. Alert on this specific error: it is the one endpoint-removal failure that actually degrades connectivity
  4. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/d4e54e62b64fff21. Report an issue: GitHub.