netbirdio/netbird · error

remove allowed IP %s on interface %s: %w

Error message

remove allowed IP %s on interface %s: %w

What it means

RemoveAllowedIP rebuilt the peer's allowed-IP list without the target prefix and asked the kernel to replace the peer's allowed IPs (ReplaceAllowedIPs:true, UpdateOnly:true), but wg.ConfigureDevice returned an error. Because the whole list is swapped in one netlink operation, one invalid surviving entry, a vanished peer or interface, or a permission problem aborts the removal. The wrapped netlink error names the concrete cause.

Source

Thrown at client/iface/configurer/kernel_unix.go:212

		if existingAllowedIP.String() == ipNet.String() {
			newAllowedIPs = append(existingPeer.AllowedIPs[:i], existingPeer.AllowedIPs[i+1:]...) //nolint:gocritic
			break
		}
	}

	peer := wgtypes.PeerConfig{
		PublicKey:         peerKeyParsed,
		UpdateOnly:        true,
		ReplaceAllowedIPs: true,
		AllowedIPs:        newAllowedIPs,
	}

	config := wgtypes.Config{
		Peers: []wgtypes.PeerConfig{peer},
	}
	err = c.configure(config)
	if err != nil {
		return fmt.Errorf("remove allowed IP %s on interface %s: %w", allowedIP, c.deviceName, err)
	}
	return nil
}

func (c *KernelConfigurer) getPeer(ifaceName, peerPubKey string) (wgtypes.Peer, error) {
	wg, err := wgctrl.New()
	if err != nil {
		return wgtypes.Peer{}, fmt.Errorf("wgctl: %w", err)
	}
	defer func() {
		err = wg.Close()
		if err != nil {
			log.Errorf("Got error while closing wgctl: %v", err)
		}
	}()

	wgDevice, err := wg.Device(ifaceName)
	if err != nil {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Read the wrapped error: ENOENT means peer/interface vanished (safe to ignore), EINVAL means a bad allowed IP, EPERM means privileges
  2. Serialize peer reconfigurations with a per-peer or per-interface mutex to avoid remove/rebuild races
  3. Re-check with FullStats and retry once if the peer still exists
  4. Run with CAP_NET_ADMIN and confirm the device with wg show
Defensive patterns

Strategy: try-catch

Try / catch

if err := kernelCfg.RemoveAllowedIP(peerKey, prefix); err != nil {
	if errors.Is(err, os.ErrNotExist) {
		// peer/interface vanished mid-operation; safe to treat as removed
		return nil
	}
	if errors.Is(err, os.ErrPermission) {
		// escalate: daemon lost privileges, do not retry
		return err
	}
	// EINVAL-style netlink rejection: dump current peers and investigate
	return err
}

Prevention

When it happens

Trigger: Peer removed concurrently between getPeer and configure (UpdateOnly:true then hits a missing peer); device deleted mid-call; an allowed-IP entry in the existing list rejected by netlink validation; EPERM without CAP_NET_ADMIN.

Common situations: Two goroutines reconfiguring the same peer during a network-map roll; interface teardown racing a route removal; running without root in a test harness that created the device earlier.

Related errors


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