netbirdio/netbird · error

remove legacy routing rule: %w

Error message

remove legacy routing rule: %w

What it means

Returned by router.RemoveNatRule when removeLegacyRouteRule fails. Note this call is unconditional: it runs even when the router is not in legacy mode, but only acts if a legacy rule key exists in r.rules (i.e. a legacy ACCEPT rule was previously installed). The inner failures are the DeleteIfExists on NETBIRD-RT-FWD-IN (error 550) or the ipset counter decrement (error 551).

Source

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

	r.updateState()

	return nil
}

// RemoveNatRule removes an iptables rule pair from forwarding and nat chains
func (r *router) RemoveNatRule(pair firewall.RouterPair) error {
	if pair.Masquerade {
		if err := r.removeNatRule(pair); err != nil {
			return fmt.Errorf("remove nat rule: %w", err)
		}

		if err := r.removeNatRule(firewall.GetInversePair(pair)); err != nil {
			return fmt.Errorf("remove inverse nat rule: %w", err)
		}
	}

	if err := r.removeLegacyRouteRule(pair); err != nil {
		return fmt.Errorf("remove legacy routing rule: %w", err)
	}

	r.updateState()

	return nil
}

// addLegacyRouteRule adds a legacy routing rule for mgmt servers pre route acls
func (r *router) addLegacyRouteRule(pair firewall.RouterPair) error {
	ruleKey := firewall.GenKey(firewall.ForwardingFormat, pair)

	if err := r.removeLegacyRouteRule(pair); err != nil {
		return err
	}

	rule := []string{"-s", pair.Source.String(), "-d", pair.Destination.String(), "-j", routingFinalForwardJump}
	if err := r.iptablesClient.Append(tableFilter, chainRTFWDIN, rule...); err != nil {
		return fmt.Errorf("add legacy forwarding rule %s -> %s: %v", pair.Source, pair.Destination, err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check which inner error fired ('remove legacy forwarding rule' vs 'decrement ipset counter') and follow its fix
  2. Verify NETBIRD-RT-FWD-IN contents: sudo iptables -S NETBIRD-RT-FWD-IN
  3. Run RemoveAllLegacyRouteRules path (full disconnect) to sweep leftovers
  4. Restart the agent to resynchronize in-memory rules with the kernel
Defensive patterns

Strategy: try-catch

Try / catch

if err := r.removeLegacyRouteRule(pair); err != nil {
	log.Warnf("legacy rule cleanup failed for %s -> %s: %v", pair.Source, pair.Destination, err)
	// not fatal for the main path; sweep later via RemoveAllLegacyRouteRules
}

Prevention

When it happens

Trigger: Removing a NAT/routing pair on a peer that earlier ran in legacyManagement mode (old management) and has a stored legacy forwarding rule. Fails when the iptables delete errors or when decrementing the set refcount errors (e.g. set in use, already destroyed).

Common situations: Management upgrade mid-session: peer installed legacy rules, management updated to route-ACL version, then rule removal hits a chain or set mutated by the earlier state; unclean shutdown leaving r.rules and kernel state diverged.

Related errors


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