netbirdio/netbird · error

invalid protocol: %w

Error message

invalid protocol: %w

What it means

Returned by applyRouteACL when convertToFirewallProtocol hits its default branch: the proto RuleProtocol value is outside {TCP, UDP, ICMP, ALL} known to this agent build. Note the function still returns ProtocolALL alongside the error, but the caller discards the rule, and because the ACL default posture is deny, the route's traffic is not permitted by this rule. New enum values are exactly how a newer management breaks an older agent here.

Source

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

	}

	var sources []netip.Prefix
	for _, sourceRange := range rule.SourceRanges {
		source, err := netip.ParsePrefix(sourceRange)
		if err != nil {
			return "", fmt.Errorf("parse source range: %w", err)
		}
		sources = append(sources, source)
	}

	destination, err := determineDestination(rule, dynamicResolver, sources)
	if err != nil {
		return "", fmt.Errorf("determine destination: %w", err)
	}

	protocol, err := convertToFirewallProtocol(rule.Protocol)
	if err != nil {
		return "", fmt.Errorf("invalid protocol: %w", err)
	}

	action, err := convertFirewallAction(rule.Action)
	if err != nil {
		return "", fmt.Errorf("invalid action: %w", err)
	}

	dPorts := convertPortInfo(rule.PortInfo)

	addedRule, err := d.firewall.AddRouteFiltering(rule.PolicyID, sources, destination, protocol, nil, dPorts, action)
	if err != nil {
		return "", fmt.Errorf("add route rule: %w", err)
	}

	return id.RuleID(addedRule.ID()), nil
}

func (d *DefaultManager) protoRuleToFirewallRule(

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Update the agent to at least the version of management in use so the enum coverage matches
  2. Set a concrete protocol (tcp/udp/icmp/all) on the affected network route policy
  3. If rolling updates take time, remove the offending policy for the lagging agents so their route rules apply cleanly
Defensive patterns

Strategy: type-guard

Validate before calling

// whitelist check before dispatching a rule to agents
var knownProtocols = map[mgmProto.RuleProtocol]bool{
    mgmProto.RuleProtocol_TCP: true,
    mgmProto.RuleProtocol_UDP: true,
    mgmProto.RuleProtocol_ICMP: true,
    mgmProto.RuleProtocol_ALL: true,
}

func protocolSupportedByAgents(p mgmProto.RuleProtocol) bool {
    return knownProtocols[p]
}

Type guard

func isKnownProtocol(p mgmProto.RuleProtocol) bool {
    switch p {
    case mgmProto.RuleProtocol_TCP, mgmProto.RuleProtocol_UDP,
        mgmProto.RuleProtocol_ICMP, mgmProto.RuleProtocol_ALL:
        return true
    }
    return false
}

Try / catch

protocol, err := convertToFirewallProtocol(rule.Protocol)
if err != nil {
    if strings.Contains(err.Error(), "invalid protocol type") {
        log.Warnf("management sent unknown protocol %d - agent older than management? rule skipped", rule.Protocol)
    }
    return "", fmt.Errorf("invalid protocol: %w", err)
}

Prevention

When it happens

Trigger: Management newer than the agent emitting a RuleProtocol the old agent's switch does not know; RuleProtocol_UNKNOWN/unset (0) reaching route ACLs from unvalidated API writes; custom management forks adding protocols.

Common situations: Partial fleet upgrades: dashboard/management already supports a new protocol, agents lag; scripts creating access policies with an empty/invalid protocol field.

Related errors


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