netbirdio/netbird · error

received error "%w" while adding allowed Ip to peer on inter

Error message

received error "%w" while adding allowed Ip to peer on interface %s with settings: allowed ips %s

What it means

Returned by KernelConfigurer.AddAllowedIP when the wgctrl/netlink call to attach an allowed IP to a peer fails. The peer config is built with UpdateOnly: true, so the kernel WireGuard module only updates a peer that already exists; patching a missing peer makes the kernel answer ENOENT, which surfaces inside this message. Other wrapped causes are a missing/renamed interface, an invalid prefix, or missing CAP_NET_ADMIN. The underlying netlink error text appears between the quotes.

Source

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

	}

	peerKeyParsed, err := wgtypes.ParseKey(peerKey)
	if err != nil {
		return err
	}
	peer := wgtypes.PeerConfig{
		PublicKey:         peerKeyParsed,
		UpdateOnly:        true,
		ReplaceAllowedIPs: false,
		AllowedIPs:        []net.IPNet{ipNet},
	}

	config := wgtypes.Config{
		Peers: []wgtypes.PeerConfig{peer},
	}
	err = c.configure(config)
	if err != nil {
		return fmt.Errorf(`received error "%w" while adding allowed Ip to peer on interface %s with settings: allowed ips %s`, err, c.deviceName, allowedIP)
	}
	return nil
}

func (c *KernelConfigurer) RemoveAllowedIP(peerKey string, allowedIP netip.Prefix) error {
	ipNet := net.IPNet{
		IP:   allowedIP.Addr().AsSlice(),
		Mask: net.CIDRMask(allowedIP.Bits(), allowedIP.Addr().BitLen()),
	}

	peerKeyParsed, err := wgtypes.ParseKey(peerKey)
	if err != nil {
		return fmt.Errorf("parse peer key: %w", err)
	}

	existingPeer, err := c.getPeer(c.deviceName, peerKey)
	if err != nil {
		return fmt.Errorf("get peer: %w", err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Create the peer first with UpdatePeer, then call AddAllowedIP, since UpdateOnly:true requires the peer to exist
  2. Verify the interface exists and is a WireGuard device: sudo wg show <deviceName> or ip link show <deviceName>
  3. Run the daemon as root or grant CAP_NET_ADMIN (container: --cap-add=NET_ADMIN)
  4. Log the wrapped netlink error to tell ENOENT (missing peer/interface) from EPERM (permissions)

Example fix

// before: peer not created yet, UpdateOnly:true makes this fail with ENOENT
err := cfg.AddAllowedIP(peerKey, prefix)

// after: create the peer first, then attach the allowed IP
if err := cfg.UpdatePeer(peerKey, []netip.Prefix{prefix}, 0, nil, nil); err != nil {
	return err
}
err = cfg.AddAllowedIP(peerKey, prefix)
Defensive patterns

Strategy: validation

Validate before calling

// ensure the peer exists before attaching an allowed IP (UpdateOnly:true requires it)
stats, err := kernelCfg.FullStats()
if err != nil {
	return err
}
exists := false
for _, p := range stats.Peers {
	if p.PublicKey == peerKey {
		exists = true
		break
	}
}
if !exists {
	// create the peer first: cfg.UpdatePeer(peerKey, nil, 0, nil, nil)
}

Try / catch

if err := cfg.AddAllowedIP(peerKey, prefix); err != nil {
	if errors.Is(err, os.ErrNotExist) {
		// peer or interface missing: create peer / interface, then retry once
	}
	return fmt.Errorf("add allowed ip %s: %w", prefix, err)
}

Prevention

When it happens

Trigger: AddAllowedIP called for a peer that was never created with UpdatePeer (UpdateOnly:true + nonexistent peer => kernel ENOENT); c.deviceName interface deleted or renamed before the call; allowedIP prefix rejected by netlink validation; ConfigureDevice returning EPERM because the process lacks CAP_NET_ADMIN.

Common situations: Route manager attaching a network-route allowed IP before the peer config sync created the peer; interface torn down concurrently during a reconnect cycle; daemon running unprivileged in a container without NET_ADMIN; custom interface name mismatch between creation and config.

Related errors


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