{"record":{"id":"51769aa920b445ec","repo":"netbirdio/netbird","slug":"set-promiscuous-mode-s","errorCode":null,"errorMessage":"set promiscuous mode: %s","messagePattern":"set promiscuous mode: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/uspfilter/forwarder/forwarder.go","lineNumber":129,"sourceCode":"\n\tdefaultSubnet, err := tcpip.NewSubnet(\n\t\ttcpip.AddrFrom4([4]byte{0, 0, 0, 0}),\n\t\ttcpip.MaskFromBytes([]byte{0, 0, 0, 0}),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating default subnet: %w\", err)\n\t}\n\n\tdefaultSubnetV6, err := tcpip.NewSubnet(\n\t\ttcpip.AddrFrom16([16]byte{}),\n\t\ttcpip.MaskFromBytes(make([]byte, 16)),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating default v6 subnet: %w\", err)\n\t}\n\n\tif err := s.SetPromiscuousMode(nicID, true); err != nil {\n\t\treturn nil, fmt.Errorf(\"set promiscuous mode: %s\", err)\n\t}\n\tif err := s.SetSpoofing(nicID, true); err != nil {\n\t\treturn nil, fmt.Errorf(\"set spoofing: %s\", err)\n\t}\n\n\ts.SetRouteTable([]tcpip.Route{\n\t\t{Destination: defaultSubnet, NIC: nicID},\n\t\t{Destination: defaultSubnetV6, NIC: nicID},\n\t})\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tf := &Forwarder{\n\t\tlogger:        logger,\n\t\tflowLogger:    flowLogger,\n\t\tstack:         s,\n\t\tendpoint:      endpoint,\n\t\tudpForwarder:  newUDPForwarder(mtu, logger, flowLogger),\n\t\tctx:           ctx,","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/uspfilter/forwarder/forwarder.go#L111-L147","documentation":"Returned when the gVisor stack refuses SetPromiscuousMode(nicID, true), which enables the NIC to accept packets addressed to any destination. The stack returns an error if the NIC ID is unknown (already removed) or the NIC endpoint does not permit the operation. Here the NIC was just created a few lines above, so failure indicates a lifecycle race or an endpoint (the WireGuard device-backed linkEndpoint) that was closed underneath the constructor.","triggerScenarios":"Concurrent Close/teardown of the engine while forwarder.New runs; the wrapped endpoint (iface.GetWGDevice()) becoming nil or closed mid-construction; a second New() after the previous forwarder tore down the same stack.","commonSituations":"Rapid netbird up/down cycles or back-to-back BindUpdate operations racing the userspace firewall initialization; mobile platforms (iOS/Android) where the interface is recreated on connectivity changes and the device handle can be invalidated quickly.","solutions":["Serialize interface bring-up and teardown so Close fully joins the old forwarder's goroutines before a new New() runs","Check that iface.GetWGDevice() returns a live device before constructing the Forwarder; skip or retry when it is nil","Retry forwarder.New once after the engine settles if the error text wraps ErrUnknownNIC/unknown device","Upgrade gVisor if the wrapped error suggests a promiscuous-mode capability regression"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// ensure the device backing the endpoint is alive before constructing\nif iface.GetWGDevice() == nil {\n    return errors.New(\"wireguard device not ready; retry after interface up\")\n}","typeGuard":"func deviceReady(iface common.IFaceMapper) bool {\n    return iface != nil && iface.GetWGDevice() != nil\n}","tryCatchPattern":"f, err := forwarder.New(...)\nif err != nil {\n    if strings.Contains(err.Error(), \"set promiscuous mode\") && deviceReady(iface) {\n        // teardown race: recreate interface and retry once\n    }\n    return err\n}","preventionTips":["Hold the engine lifecycle mutex across New/Stop so they cannot interleave","Join the previous forwarder's goroutines (done channel) before rebuilding","Retry bring-up once after the interface settles instead of failing hard on the race"],"tags":["go","netbird","gvisor","netstack","race","firewall"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}