{"record":{"id":"e4b06ca4013b8a9e","repo":"cilium/cilium","slug":"interface-q-peer-count-mismatch-s-d-s-d","errorCode":null,"errorMessage":"interface %q: peer count mismatch (%s=%d, %s=%d)","messagePattern":"interface %q: peer count mismatch \\((.+?)=(.+?), (.+?)=(.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cilium-dbg/cmd/encrypt_status.go","lineNumber":134,"sourceCode":"\t\treturn nil\n\t}\n\n\tcompareIfaces := func(from, to []*models.WireguardInterface, fromLabel, toLabel string) {\n\t\tfor _, f := range from {\n\t\t\tif _, seen := seenIfaces[f.Name]; seen {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tseenIfaces[f.Name] = struct{}{}\n\n\t\t\tt := findIface(to, f.Name)\n\t\t\tif t == nil {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"interface %q exists in %s but is missing in %s\",\n\t\t\t\t\tf.Name, fromLabel, toLabel))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif f.PeerCount != t.PeerCount {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"interface %q: peer count mismatch (%s=%d, %s=%d)\",\n\t\t\t\t\tf.Name, fromLabel, f.PeerCount, toLabel, t.PeerCount))\n\t\t\t}\n\t\t\tif f.ListenPort != t.ListenPort {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"interface %q: listen port mismatch (%s=%d, %s=%d)\",\n\t\t\t\t\tf.Name, fromLabel, f.ListenPort, toLabel, t.ListenPort))\n\t\t\t}\n\t\t\tif f.PublicKey != t.PublicKey {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"interface %q: public key mismatch (%s=%s, %s=%s)\",\n\t\t\t\t\tf.Name, fromLabel, f.PublicKey, toLabel, t.PublicKey))\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(agent.Interfaces) != len(kernel.Interfaces) {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"interface count mismatch (agent=%d, kernel=%d)\",\n\t\t\tlen(agent.Interfaces), len(kernel.Interfaces)))\n\t}\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/cilium-dbg/cmd/encrypt_status.go#L116-L152","documentation":"compareIfaces in validateWireguardStates matches interfaces by name across the agent-reported and kernel-read WireGuard status, then compares fields. This error is joined when both sides report the same interface but with a different PeerCount, i.e. the agent believes a different number of public keys/peers are attached to the device than the kernel actually has.","triggerScenarios":"`cilium encrypt status` in wireguard mode where models.WireguardInterface.PeerCount for the same-named interface differs between agent healthz payload and wgctrl device dump — typically when a peer is (or was just) added/removed and the agent's view is out of sync with the live kernel device.","commonSituations":"Node peer configuration changed (node added/removed from cluster) and the agent is mid-update or stuck; failed peer reconciliation after Cilium config change; stale agent healthz data after the interface was re-keyed externally with `wg` or `wg-quick`; version skew between agent components.","solutions":["Inspect the actual peer list (`wg show cilium_wg0`) versus agent logs to identify which peer is missing/extra; restart the agent to force peer re-derivation from cluster state.","Check agent logs for WireGuard peer reconciliation errors and fix the underlying cause (e.g. node public key rotation failures) before restarting.","If keys were rotated externally, restart the agent so it re-programs the correct peer set on the kernel device.","Upgrade mismatched Cilium versions in the cluster so agent and datapath conventions match."],"exampleFix":"// before\nMsg: ... interface \"cilium_wg0\": peer count mismatch (agent=5, kernel=4)\n// after: restart agent to reconcile peers\n$ kubectl -n kube-system rollout restart daemonset/cilium\n$ wg show cilium_wg0 peers | wc -l","handlingStrategy":"validation","validationCode":"// Compare peer counts on both sides before trusting the state\nwgOut, _ := exec.Command(\"wg\", \"show\", \"cilium_wg0\", \"peers\").Output()\nkernelPeers := len(strings.Fields(string(wgOut)))\nfor _, i := range agent.Interfaces {\n    if i.Name == \"cilium_wg0\" && int(i.PeerCount) != kernelPeers {\n        fmt.Println(\"agent peer count out of sync with kernel; restart agent\")\n    }\n}","typeGuard":"func peerCountMatches(a, k *models.WireguardInterface) bool {\n    return a != nil && k != nil && a.PeerCount == k.PeerCount\n}","tryCatchPattern":"if err := validateWireguardStates(agent, kernel); err != nil {\n    if strings.Contains(err.Error(), \"peer count mismatch\") {\n        // reconcile: restart agent to re-derive peers from cluster state\n    }\n}","preventionTips":["Let Cilium manage all WireGuard peers; never modify peers with `wg set` directly.","Watch agent logs for peer reconciliation errors after node add/remove events.","Re-run `cilium encrypt status` after cluster topology changes to catch drift early.","Avoid interrupting agent restarts mid key/peer programming."],"tags":["wireguard","cilium","peer-count","state-mismatch","cli"],"backgroundTag":"wireguard-state-mismatch","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}