netbirdio/netbird · warning

check chain %s: %w

Error message

check chain %s: %w

What it means

Returned by router.cleanUpDefaultForwardRules when iptablesClient.ChainExists(tableNat, NETBIRD-NAT-OUTPUT) errors. This is a query failure, not a chain-presence result: the go-iptables ChainExists call itself could not run (iptables binary/lock/permission problem). It gates removal of the '-j NETBIRD-NAT-OUTPUT' jump from the OUTPUT chain.

Source

Thrown at client/firewall/iptables/router_linux.go:406

	}

	r.rules = make(map[string][]string)
	r.updateState()

	return nberrors.FormatErrorOrNil(merr)
}

func (r *router) cleanUpDefaultForwardRules() error {
	if err := r.cleanJumpRules(); err != nil {
		return fmt.Errorf("clean jump rules: %w", err)
	}

	log.Debug("flushing routing related tables")

	// Remove jump rules from built-in chains before deleting custom chains,
	// otherwise the chain deletion fails with "device or resource busy".
	if ok, err := r.iptablesClient.ChainExists(tableNat, chainNATOutput); err != nil {
		return fmt.Errorf("check chain %s: %w", chainNATOutput, err)
	} else if ok {
		jumpRule := []string{"-j", chainNATOutput}
		if err := r.iptablesClient.Delete(tableNat, "OUTPUT", jumpRule...); err != nil {
			log.Debugf("clean OUTPUT jump rule: %v", err)
		}
	}

	for _, chainInfo := range []struct {
		chain string
		table string
	}{
		{chainRTFWDIN, tableFilter},
		{chainRTFWDOUT, tableFilter},
		{chainRTPRE, tableMangle},
		{chainRTNAT, tableNat},
		{chainRTRDR, tableNat},
		{chainNATOutput, tableNat},
		{chainRTMSSCLAMP, tableMangle},

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Run the probe manually: sudo iptables -t nat -S OUTPUT to reproduce the backend error
  2. Ensure iptables/nft binaries are installed and on PATH for the daemon
  3. Free the xtables lock and retry agent start
  4. Check daemon unit for capability restrictions (needs CAP_NET_ADMIN)
Defensive patterns

Strategy: fallback

Validate before calling

// preflight iptables operability
sudo iptables -t nat -S OUTPUT >/dev/null || echo "iptables backend broken"

Try / catch

if ok, err := r.iptablesClient.ChainExists(tableNat, chainNATOutput); err != nil {
	// query failure: skip OUTPUT jump cleanup rather than aborting the whole teardown
	log.Debugf("check chain %s: %v", chainNATOutput, err)
} else if ok {
	_ = r.iptablesClient.Delete(tableNat, "OUTPUT", "-j", chainNATOutput)
}

Prevention

When it happens

Trigger: During init cleanup or Reset, the nat-table list operation fails: iptables binary missing from PATH in minimal containers, xtables lock held, CAP_NET_ADMIN lost, or nft backend errors listing the table.

Common situations: Containers with truncated PATH or without the iptables package; agents whose privileges were dropped (systemd RestrictCapabilities); hosts with corrupted nft rulesets.

Related errors


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