netbirdio/netbird · error
create nftables manager: %w
Error message
create nftables manager: %w
What it means
Raised in ShutdownState.Cleanup (client/firewall/nftables/state_linux.go:39) during crash-recovery: the agent persisted its nftables state before a shutdown, and on the next start it recreates a full nftables manager from that InterfaceState just to Close it (which flushes the leftover netbird rules/table). Create performs the whole table/chain setup over netlink and fails without CAP_NET_ADMIN, without kernel nftables support, or on any netlink handshake error.
Source
Thrown at client/firewall/nftables/state_linux.go:39
return i.WGAddress
}
type ShutdownState struct {
InterfaceState *InterfaceState `json:"interface_state,omitempty"`
}
func (s *ShutdownState) Name() string {
return "nftables_state"
}
func (s *ShutdownState) Cleanup() error {
mtu := s.InterfaceState.MTU
if mtu == 0 {
mtu = iface.DefaultMTU
}
nft, err := Create(s.InterfaceState, mtu)
if err != nil {
return fmt.Errorf("create nftables manager: %w", err)
}
if err := nft.Close(nil); err != nil {
return fmt.Errorf("reset nftables manager: %w", err)
}
return nil
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Run the recovery with the same privileges the agent had when it wrote the state (root or CAP_NET_ADMIN)
- Verify nftables availability first: 'nft list ruleset' as the same user; load nf_tables module if missing
- If the environment intentionally lost nftables support, clear the persisted shutdown state file so cleanup is skipped on subsequent starts
- Log and continue (the leftover rules die with the old table lifetime / reboot) rather than blocking agent startup on cleanup failure
Example fix
// before
nft, err := Create(s.InterfaceState, mtu)
if err != nil {
return fmt.Errorf("create nftables manager: %w", err)
}
// after - skip cleanup when nftables is unavailable in the current environment
if !nftablesAvailable() {
log.Warn("nftables unavailable, skipping shutdown-state cleanup")
return nil
}
nft, err := Create(s.InterfaceState, mtu)
if err != nil {
return fmt.Errorf("create nftables manager: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
// before attempting crash-recovery cleanup
if os.Geteuid() != 0 && !hasCapNetAdmin() {
log.Warn("skipping nftables shutdown-state cleanup: insufficient privileges")
return nil
} Type guard
func nftablesAvailable() bool {
f, err := os.Open("/proc/net/netfilter/nfnetlink_queue")
if err == nil {
f.Close()
}
c, err := net.Dial("unix", "") // probe replaced by exec probe below
_ = c
return exec.Command("nft", "list", "ruleset").Run() == nil
} Try / catch
if err := shutdownState.Cleanup(); err != nil {
if isPermissionErr(err) || isNotExistErr(err) {
log.Warnf("nftables cleanup skipped: %v", err)
return // do not block startup on cleanup
}
return err
} Prevention
- Preserve agent privileges between the crash and the recovery run
- Run 'netbird service reinstall' after capability changes instead of manual restarts
- Clear persisted shutdown state when migrating to environments without nftables
When it happens
Trigger: Agent restarted after a crash/kill without root privileges; recovery running inside a container or VM where nftables was present at write time but absent at restore time (kernel/module change, bind-mount restrictions); netlink socket creation blocked by seccomp.
Common situations: Host downgraded or kernel changed between runs; systemd unit lost AmbientCapabilities; agent running in privileged container where nftables module is not loaded; 'netbird down' invoked by an unprivileged helper triggering state restore.
Related errors
- add output DNAT rule: %w
- reset nftables manager: %w
- create ipset: %w
- failed to check rule: %w
- create ipset %s: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/4cb2b51a8c97c590.
Report an issue: GitHub.