netbirdio/netbird · error

add route rule: %w

Error message

add route rule: %w

What it means

Appended per-rule in applyRouteACLs when applyRouteACL fails for a route-firewall (distribution policy) rule. It wraps every failure inside that helper: parse source range, determine destination, invalid protocol/action, and `add route rule` from firewall.AddRouteFiltering itself. ErrSourceRangesEmpty is deliberately excluded (skipped at debug), so seeing this error means a real parsing or backend problem. Failed rules are not inserted into newRouteRules, so the route ACL is not enforced for that traffic.

Source

Thrown at client/internal/acl/manager.go:218

			}
			delete(d.peerRulesPairs, pairID)
		}
	}
	d.peerRulesPairs = newRulePairs
}

func (d *DefaultManager) applyRouteACLs(rules []*mgmProto.RouteFirewallRule, dynamicResolver bool) error {
	newRouteRules := make(map[id.RuleID]struct{}, len(rules))
	var merr *multierror.Error

	// Apply new rules - firewall manager will return existing rule ID if already present
	for _, rule := range rules {
		id, err := d.applyRouteACL(rule, dynamicResolver)
		if err != nil {
			if errors.Is(err, ErrSourceRangesEmpty) {
				log.Debugf("skipping empty sources rule with destination %s: %v", rule.Destination, err)
			} else {
				merr = multierror.Append(merr, fmt.Errorf("add route rule: %w", err))
			}
			continue
		}
		newRouteRules[id] = struct{}{}
	}

	// Clean up old firewall rules
	for id := range d.routeRules {
		if _, exists := newRouteRules[id]; !exists {
			if err := d.firewall.DeleteRouteRule(id); err != nil {
				merr = multierror.Append(merr, fmt.Errorf("delete route rule: %w", err))
			}
			// implicitly deleted from the map
		}
	}

	d.routeRules = newRouteRules
	return nberrors.FormatErrorOrNil(merr)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Unwrap the %w chain in the engine logs - the inner message names the exact field (source range, destination, protocol) or the backend
  2. Fix the offending policy field in management (valid CIDR, known protocol)
  3. Update the agent so its RuleProtocol/RuleAction enums cover what management emits
  4. Verify firewall backend health with `nft list ruleset` / `iptables-save` and agent capabilities
Defensive patterns

Strategy: try-catch

Validate before calling

// management-side guard for route firewall rules
func validRouteRule(r *mgmProto.RouteFirewallRule) error {
    if len(r.SourceRanges) == 0 {
        return errors.New("no source ranges")
    }
    for _, s := range r.SourceRanges {
        if _, err := netip.ParsePrefix(s); err != nil {
            return fmt.Errorf("source %q: %w", s, err)
        }
    }
    if !r.IsDynamic {
        if _, err := netip.ParsePrefix(r.Destination); err != nil {
            return fmt.Errorf("destination %q: %w", r.Destination, err)
        }
    }
    return nil
}

Try / catch

if err := d.applyRouteACLs(rules, dyn); err != nil {
    var merr *multierror.Error
    if errors.As(err, &merr) {
        for _, e := range merr.Errors {
            switch {
            case strings.Contains(e.Error(), "parse source range"),
                strings.Contains(e.Error(), "determine destination"),
                strings.Contains(e.Error(), "invalid protocol"):
                log.Errorf("management sent malformed rule - fix policy: %v", e)
            case strings.Contains(e.Error(), "add route rule"):
                log.Errorf("firewall backend rejected rule: %v", e)
            case strings.Contains(e.Error(), "delete route rule"):
                log.Warnf("reconcile divergence: %v", e)
            }
        }
    }
}

Prevention

When it happens

Trigger: Management sending a RouteFirewallRule with any malformed field (bad CIDR in SourceRanges or Destination, protocol enum the agent does not know), or the firewall backend failing AddRouteFiltering (nftables/iptables error, full ruleset).

Common situations: Network routes (access control policies on routing groups) configured after a management upgrade while agents lag behind; API-authored policies with invalid CIDRs; hosts where the firewall backend is degraded.

Related errors


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