netbirdio/netbird · error

failed to remove peer: %s

Error message

failed to remove peer: %s

What it means

The first phase of WGUSPConfigurer.RemoveEndpointAddress, an IpcSet with remove=true, failed, so the peer could not be removed before being re-added without an endpoint. wireguard-go rejects the removal mainly when the device is closed or the generated UAPI line is malformed. Note the message formats with %s instead of %w, so errors.Is/As cannot see the underlying cause through this wrapper.

Source

Thrown at client/iface/configurer/usp.go:172

			found = true
			break
		}
	}
	if !found {
		return fmt.Errorf("peer %s not found", peerKey)
	}

	// remove the peer from the WireGuard configuration
	peer := wgtypes.PeerConfig{
		PublicKey: peerKeyParsed,
		Remove:    true,
	}

	config := wgtypes.Config{
		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

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Ensure the device is still running before mutating peers; skip cleanup after Close
  2. Change the wrapper to %w so callers can branch on the real cause (upstream fix)
  3. Log the raw ipcErr string since no wrapping is currently preserved
  4. Retry once if the failure coincided with a device restart

Example fix

// before: %s destroys the error chain
return fmt.Errorf("failed to remove peer: %s", ipcErr)

// after: wrap with %w
return fmt.Errorf("remove peer %s: %w", peerKey, ipcErr)
Defensive patterns

Strategy: try-catch

Try / catch

if err := uspCfg.RemoveEndpointAddress(peerKey); err != nil {
	// NOTE: this error wraps with %s upstream, so errors.Is will not match the cause;
	// match on message text or fix the wrapper to %w
	if strings.Contains(err.Error(), "failed to remove peer") {
		// device likely closed mid-operation: verify lifecycle, then retry once if alive
	}
	return err
}

Prevention

When it happens

Trigger: Device closed or closing when IpcSet(remove=true) runs; public key serialized incorrectly into the public_key= line; a wireguard-go internal state error surfaced by IpcSet.

Common situations: Endpoint cleanup racing device Close during shutdown; version-skewed wireguard-go rejecting a line the builder emits; tests driving the configurer against a fake device that errors on IpcSet.

Related errors


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