netbirdio/netbird · error

init ip6tables: %w

Error message

init ip6tables: %w

What it means

iptables.NewWithProtocol(ProtocolIPv6) failed inside createIPv6Components: go-iptables could not find or execute a usable ip6tables binary (or its nft variant) or could not parse `ip6tables --version`. This runs only when the interface has an IPv6 address, so v4-only hosts never hit it, but any dual-stack host without the v6 binary fails manager creation.

Source

Thrown at client/firewall/iptables/manager_linux.go:82

	m.aclMgr, err = newAclManager(iptablesClient, wgIface)
	if err != nil {
		return nil, fmt.Errorf("create acl manager: %w", err)
	}

	if wgIface.Address().HasIPv6() {
		if err := m.createIPv6Components(wgIface, mtu); err != nil {
			return nil, fmt.Errorf("create IPv6 firewall: %w", err)
		}
	}

	return m, nil
}

func (m *Manager) createIPv6Components(wgIface iFaceMapper, mtu uint16) error {
	ip6Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv6)
	if err != nil {
		return fmt.Errorf("init ip6tables: %w", err)
	}
	m.ipv6Client = ip6Client

	m.router6, err = newRouter(ip6Client, wgIface, mtu)
	if err != nil {
		return fmt.Errorf("create v6 router: %w", err)
	}

	// Share the same IP forwarding state with the v4 router, since
	// Forwarding refcounter is per-family but shared between v4 and v6 routers.
	m.router6.ipFwdState = m.router.ipFwdState

	m.aclMgr6, err = newAclManager(ip6Client, wgIface)
	if err != nil {
		return fmt.Errorf("create v6 acl manager: %w", err)
	}

	return nil

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Install ip6tables alongside iptables in the image/host (e.g. `apk add ip6tables` or the iptables package's v6 component).
  2. Fix the service PATH to include /usr/sbin, /sbin.
  3. Verify with `ip6tables --version` under the daemon's user and environment.
  4. If v6 is not actually needed, remove the v6 address from the NetBird interface to skip this path entirely.

Example fix

# alpine image
RUN apk add --no-cache iptables ip6tables ipset

# debian image
RUN apt-get update && apt-get install -y iptables ip6tables ipset
Defensive patterns

Strategy: validation

Validate before calling

func verifyIp6tablesBinary() error {
    p, err := exec.LookPath("ip6tables")
    if err != nil {
        return fmt.Errorf("ip6tables not found (required when the interface has an IPv6 address): %w", err)
    }
    if out, err := exec.Command(p, "--version").CombinedOutput(); err != nil {
        return fmt.Errorf("ip6tables --version failed: %s: %w", out, err)
    }
    return nil
}

// call before iptables.Create() when the overlay is dual-stack

Try / catch

if _, err := iptablesMgr.Create(wgIface, mtu); err != nil {
    if strings.Contains(err.Error(), "init ip6tables") {
        // install the v6 binary or drop the interface's v6 address to skip the v6 path
        log.Fatalf("ip6tables unavailable but interface is dual-stack: %v", err)
    }
}

Prevention

When it happens

Trigger: Interface has a v6 address but ip6tables is not installed or not in the daemon's PATH; ip6tables exists but is a broken symlink/wrapper; version output unparseable (nonstandard wrapper scripts).

Common situations: Images that install `iptables` but not `ip6tables`; service units with minimal PATH; custom busybox wrappers; nft-only systems missing ip6tables-nft.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/c751cea5853bb778. Report an issue: GitHub.