{"record":{"id":"9d0172f71aae1cac","repo":"netbirdio/netbird","slug":"get-ipc-config-w","errorCode":null,"errorMessage":"get IPC config: %w","messagePattern":"get IPC config: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/configurer/usp.go","lineNumber":140,"sourceCode":"\t\taddr, err := netip.ParseAddr(endpoint.IP.String())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse endpoint address: %w\", err)\n\t\t}\n\t\taddrPort := netip.AddrPortFrom(addr.Unmap(), uint16(endpoint.Port))\n\t\tc.activityRecorder.UpsertAddress(peerKey, addrPort)\n\t}\n\treturn nil\n}\n\nfunc (c *WGUSPConfigurer) RemoveEndpointAddress(peerKey string) error {\n\tpeerKeyParsed, err := wgtypes.ParseKey(peerKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse peer key: %w\", err)\n\t}\n\n\tipcStr, err := c.device.IpcGet()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get IPC config: %w\", err)\n\t}\n\n\t// Parse current status to get allowed IPs for the peer\n\tstats, err := parseStatus(c.deviceName, ipcStr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse IPC config: %w\", err)\n\t}\n\n\tvar allowedIPs []net.IPNet\n\tfound := false\n\tfor _, peer := range stats.Peers {\n\t\tif peer.PublicKey == peerKey {\n\t\t\tallowedIPs = peer.AllowedIPs\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !found {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/configurer/usp.go#L122-L158","documentation":"WGUSPConfigurer.RemoveEndpointAddress could not read the current configuration from the in-process wireguard-go device via device.IpcGet(). The dump is needed to preserve the peer's allowed IPs across the remove/re-add cycle that clears the endpoint. IpcGet fails chiefly when the device is closed or its state is torn down mid-call, since the configurer and the wireguard-go device share one process lifetime.","triggerScenarios":"RemoveEndpointAddress invoked after the wireguard-go device was Closed; Close racing the call; device in a half-initialized state after a failed ConfigureInterface.","commonSituations":"Teardown ordering bugs where connection cleanup runs after iface Close; reconnect flow rebuilding the device while stale peer handlers still fire; embedded/netstack clients tearing down quickly.","solutions":["Order teardown: clear peer endpoints before closing the wireguard-go device","Check whether the device is already closed and skip endpoint cleanup then","Retry once after the device is confirmed running","Log the raw IpcGet error to distinguish 'closed' from serialization failures"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := uspCfg.RemoveEndpointAddress(peerKey); err != nil {\n\tif strings.Contains(err.Error(), \"get IPC config\") {\n\t\t// device likely closed: verify lifecycle before retrying\n\t\treturn fmt.Errorf(\"device state unreadable; is the device closed? %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Clear peer endpoints before closing the wireguard-go device in teardown order","Guard configurer calls with a 'device running' flag set false on Close","Keep a single owner goroutine for device mutation to avoid Close races","Retry once only after confirming the device is still alive"],"tags":["wireguard-go","userspace","uapi","lifecycle","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}