netbirdio/netbird · error
parse peer key: %w
Error message
parse peer key: %w
What it means
WGUSPConfigurer.RemoveEndpointAddress could not parse the peer key with wgtypes.ParseKey, which requires a base64-encoded 32-byte key string. Any other encoding (notably the hex form used in wireguard-go UAPI lines), truncation, whitespace, or an empty string fails here before the IPC dump is read. It is the userspace twin of the parse error in the kernel configurer's RemoveAllowedIP.
Source
Thrown at client/iface/configurer/usp.go:135
if ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {
return ipcErr
}
if endpoint != nil {
addr, err := netip.ParseAddr(endpoint.IP.String())
if err != nil {
return fmt.Errorf("failed to parse endpoint address: %w", err)
}
addrPort := netip.AddrPortFrom(addr.Unmap(), uint16(endpoint.Port))
c.activityRecorder.UpsertAddress(peerKey, addrPort)
}
return nil
}
func (c *WGUSPConfigurer) RemoveEndpointAddress(peerKey string) error {
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
if err != nil {
return fmt.Errorf("parse peer key: %w", err)
}
ipcStr, err := c.device.IpcGet()
if err != nil {
return fmt.Errorf("get IPC config: %w", err)
}
// Parse current status to get allowed IPs for the peer
stats, err := parseStatus(c.deviceName, ipcStr)
if err != nil {
return fmt.Errorf("parse IPC config: %w", err)
}
var allowedIPs []net.IPNet
found := false
for _, peer := range stats.Peers {
if peer.PublicKey == peerKey {
allowedIPs = peer.AllowedIPsView on GitHub (pinned to 93e97f4bf1)
Solutions
- Validate once at ingestion with wgtypes.ParseKey and store key.String()
- Convert hex keys explicitly via hex.DecodeString + wgtypes.NewKey
- Trim whitespace and reject empty keys at the boundary that produces peer keys
Example fix
// before
err := cfg.RemoveEndpointAddress(hexKey)
// after
b, err := hex.DecodeString(hexKey)
if err != nil {
return err
}
k, err := wgtypes.NewKey(b)
if err != nil {
return err
}
err = cfg.RemoveEndpointAddress(k.String()) Defensive patterns
Strategy: validation
Validate before calling
// normalize the key before calling into the userspace configurer
parsed, err := wgtypes.ParseKey(peerKey)
if err != nil {
return fmt.Errorf("bad peer key from upstream: %w", err)
}
return uspCfg.RemoveEndpointAddress(parsed.String()) Type guard
func isValidWGPeerKey(s string) bool {
_, err := wgtypes.ParseKey(s)
return err == nil
} Try / catch
if err := uspCfg.RemoveEndpointAddress(peerKey); err != nil {
if _, perr := wgtypes.ParseKey(peerKey); perr != nil {
// producer bug: fix key format at source, retrying will not help
return fmt.Errorf("peer key malformed upstream: %w", perr)
}
return err
} Prevention
- Accept only wgtypes.Key.String() output as the canonical peer-key format in your code
- Convert hex keys at the UAPI boundary, never inside configurer calls
- Fuzz-test key ingestion with the exact formats your producers emit
- Fail fast on malformed keys at ingress with a clear log of the offending length
When it happens
Trigger: Hex-encoded peer key passed where base64 is expected; key copied from a public_key=<hex> UAPI line; empty or truncated key from an upstream payload; whitespace or newline appended to the key.
Common situations: Sharing key strings between kernel-mode and userspace-mode code paths without format conversion; management or test fixtures supplying malformed keys; keys logged and re-read with formatting artifacts.
Related errors
- parse peer key: %w
- failed to parse endpoint address: %w
- error configuring interface: %s
- error configuring interface: %s
- connector type change not allowed
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/3020eded88cac40f.
Report an issue: GitHub.