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 nilView on GitHub (pinned to 93e97f4bf1)
Solutions
- Ensure the device is still running before mutating peers; skip cleanup after Close
- Change the wrapper to %w so callers can branch on the real cause (upstream fix)
- Log the raw ipcErr string since no wrapping is currently preserved
- 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
- Use %w (not %s) when wrapping IpcSet errors so errors.Is/As keep working
- Verify the device is running before two-phase peer mutations
- Serialize IpcSet sequences per peer to avoid interleaved remove/re-add
- Include the peer key in the message to make logs actionable
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.