{"record":{"id":"d4e54e62b64fff21","repo":"netbirdio/netbird","slug":"error-re-adding-peer-s-to-interface-s-with-allow","errorCode":null,"errorMessage":"error re-adding peer %s to interface %s with allowed IPs %v: %w","messagePattern":"error re-adding peer (.+?) to interface (.+?) with allowed IPs (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/configurer/kernel_unix.go","lineNumber":118,"sourceCode":"\n\tremovePeerCfg := wgtypes.PeerConfig{\n\t\tPublicKey: peerKeyParsed,\n\t\tRemove:    true,\n\t}\n\n\tif err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{removePeerCfg}}); err != nil {\n\t\treturn fmt.Errorf(`error removing peer %s from interface %s: %w`, peerKey, c.deviceName, err)\n\t}\n\n\t//Re-add the peer without the endpoint but same AllowedIPs\n\treAddPeerCfg := wgtypes.PeerConfig{\n\t\tPublicKey:         peerKeyParsed,\n\t\tAllowedIPs:        existingPeer.AllowedIPs,\n\t\tReplaceAllowedIPs: true,\n\t}\n\n\tif err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); err != nil {\n\t\treturn fmt.Errorf(\n\t\t\t`error re-adding peer %s to interface %s with allowed IPs %v: %w`,\n\t\t\tpeerKey, c.deviceName, existingPeer.AllowedIPs, err,\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc (c *KernelConfigurer) RemovePeer(peerKey string) error {\n\tpeerKeyParsed, err := wgtypes.ParseKey(peerKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpeer := wgtypes.PeerConfig{\n\t\tPublicKey: peerKeyParsed,\n\t\tRemove:    true,\n\t}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/configurer/kernel_unix.go#L100-L136","documentation":"The second half of RemoveEndpointAddress (re-adding the peer with its original allowed IPs but no endpoint) failed after the peer had already been removed. Unlike the remove step, this error leaves the device in a degraded state: the peer is gone from WireGuard, so its routes/allowed IPs no longer match until the operation succeeds. Recovery requires re-adding the peer, either by retrying or by triggering a full peer resync from the network map.","triggerScenarios":"Device removed or permissions lost between the remove and re-add configures; an allowed-IP list that the kernel now rejects (e.g. family/mask corruption) even though it was read straight from getPeer; netlink failure under memory pressure or concurrent updates.","commonSituations":"Teardown racing endpoint cleanup during shutdown or reconnection; long-lived agents that accumulated unusual allowed-IP sets; hosts with flaky uapi/netlink transports.","solutions":["Retry the re-add immediately with the same peer config; the inputs (existingPeer.AllowedIPs) are already captured","If retry keeps failing, trigger a full peer resync (re-apply all peers from the network map) to restore the device","Alert on this specific error: it is the one endpoint-removal failure that actually degrades connectivity","Check device existence and privileges before retrying so you do not loop on a permanent cause"],"exampleFix":"// before\nif err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); err != nil {\n    return fmt.Errorf(`error re-adding peer %s ...`, peerKey, c.deviceName, existingPeer.AllowedIPs, err)\n}\n\n// after\nif err := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); err != nil {\n    if retryErr := c.configure(wgtypes.Config{Peers: []wgtypes.PeerConfig{reAddPeerCfg}}); retryErr != nil {\n        return fmt.Errorf(`error re-adding peer %s ...: %w (retry: %v)`, peerKey, c.deviceName, existingPeer.AllowedIPs, err, retryErr)\n    }\n}","handlingStrategy":"retry","validationCode":"// before the whole remove/re-add, capture the desired end state\nexisting, err := getPeer(deviceName, peerKey)\nif err != nil { return err }\ndesired := wgtypes.PeerConfig{\n    PublicKey: existing.PublicKey,\n    AllowedIPs: existing.AllowedIPs,\n    ReplaceAllowedIPs: true,\n} // on any later failure, re-apply this config to restore the peer","typeGuard":"func deviceCanBeConfigured(name string) bool {\n    client, err := wgctrl.New()\n    if err != nil {\n        return false\n    }\n    defer client.Close()\n    _, err = client.Device(name)\n    return err == nil\n}","tryCatchPattern":"if err := configurer.RemoveEndpointAddress(peerKey); err != nil {\n    if strings.Contains(err.Error(), \"re-adding peer\") {\n        // peer is currently absent: re-apply desired config immediately\n        if retryErr := reapplyPeer(desired); retryErr != nil {\n            return fmt.Errorf(\"peer %s left off-device: %w\", peerKey, err)\n        }\n        return nil\n    }\n    return err\n}","preventionTips":["Treat 'error re-adding peer' as a connectivity-loss event: alert and self-heal by re-applying the peer config","Keep the captured allowed IPs from getPeer available for recovery until the operation succeeds","Retry bounded (2-3 attempts) then escalate to a full peer resync from the network map","Avoid interleaving endpoint removal with engine restarts"],"tags":["go","netbird","wireguard","kernel","peers","state-loss"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}