{"record":{"id":"bb79007c1df343b8","repo":"netbirdio/netbird","slug":"parse-peer-key-w","errorCode":null,"errorMessage":"parse peer key: %w","messagePattern":"parse peer key: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/configurer/kernel_unix.go","lineNumber":183,"sourceCode":"\tconfig := wgtypes.Config{\n\t\tPeers: []wgtypes.PeerConfig{peer},\n\t}\n\terr = c.configure(config)\n\tif err != nil {\n\t\treturn fmt.Errorf(`received error \"%w\" while adding allowed Ip to peer on interface %s with settings: allowed ips %s`, err, c.deviceName, allowedIP)\n\t}\n\treturn nil\n}\n\nfunc (c *KernelConfigurer) RemoveAllowedIP(peerKey string, allowedIP netip.Prefix) error {\n\tipNet := net.IPNet{\n\t\tIP:   allowedIP.Addr().AsSlice(),\n\t\tMask: net.CIDRMask(allowedIP.Bits(), allowedIP.Addr().BitLen()),\n\t}\n\n\tpeerKeyParsed, err := wgtypes.ParseKey(peerKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse peer key: %w\", err)\n\t}\n\n\texistingPeer, err := c.getPeer(c.deviceName, peerKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get peer: %w\", err)\n\t}\n\n\tnewAllowedIPs := existingPeer.AllowedIPs\n\n\tfor i, existingAllowedIP := range existingPeer.AllowedIPs {\n\t\tif existingAllowedIP.String() == ipNet.String() {\n\t\t\tnewAllowedIPs = append(existingPeer.AllowedIPs[:i], existingPeer.AllowedIPs[i+1:]...) //nolint:gocritic\n\t\t\tbreak\n\t\t}\n\t}\n\n\tpeer := wgtypes.PeerConfig{\n\t\tPublicKey:         peerKeyParsed,","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/configurer/kernel_unix.go#L165-L201","documentation":"RemoveAllowedIP could not parse the peer public key with wgtypes.ParseKey. wgtypes.ParseKey accepts only a base64-encoded 32-byte key (44 characters ending in '='), the format wgtypes.Key.String() produces. Hex-encoded keys, truncated strings, whitespace, or empty input all fail here before any device interaction happens.","triggerScenarios":"Passing the hex form of the key (64 hex chars, as used in wireguard-go UAPI public_key= lines) where base64 is required; peer key truncated or with trailing whitespace/newline; empty peerKey string; key sourced from a different serialization format.","commonSituations":"Copying keys between the kernel configurer (base64) and userspace UAPI dumps (hex) without converting; management payload carrying a malformed key; test fixtures using placeholder strings like 'testkey'.","solutions":["Validate keys once at the boundary with wgtypes.ParseKey and pass key.String() onward","If the key is hex, convert it first: bytes, err := hex.DecodeString(hexKey) then wgtypes.NewKey(bytes)","Check the upstream producer (network map handling) for truncation or formatting of peer keys"],"exampleFix":"// before: hex key from a UAPI dump fails base64 parsing\nerr := cfg.RemoveAllowedIP(hexKey, prefix)\n\n// after: convert hex to a wgtypes key once at the boundary\nb, err := hex.DecodeString(hexKey)\nif err != nil {\n\treturn err\n}\nkey, err := wgtypes.NewKey(b)\nif err != nil {\n\treturn err\n}\nerr = cfg.RemoveAllowedIP(key.String(), prefix)","handlingStrategy":"validation","validationCode":"// validate/normalize once at the boundary before any configurer call\nparsedKey, err := wgtypes.ParseKey(peerKey)\nif err != nil {\n\treturn fmt.Errorf(\"reject malformed peer key: %w\", err)\n}\npeerKey = parsedKey.String()","typeGuard":"func isValidWGPeerKey(s string) bool {\n\t_, err := wgtypes.ParseKey(s)\n\treturn err == nil\n}","tryCatchPattern":"if err := cfg.RemoveAllowedIP(peerKey, prefix); err != nil {\n\tif strings.Contains(err.Error(), \"parse peer key\") {\n\t\t// key format bug upstream: fix the producer, do not retry\n\t}\n\treturn err\n}","preventionTips":["Parse peer keys once where they enter the system and pass key.String() everywhere after","Convert hex UAPI keys to wgtypes.Key with hex.DecodeString + wgtypes.NewKey, never mix formats","Trim whitespace on keys coming from config files or IPC payloads","Add a unit test asserting wgtypes.ParseKey accepts every key your pipeline produces"],"tags":["wireguard","key-parsing","base64","go","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}