juanfont/headscale · error · ErrInvalidProtocolNumber

%w: %q must be a known protocol name or valid protocol numbe

Error message

%w: %q must be a known protocol name or valid protocol number 0-255

What it means

Protocol.validate fell through the known-name list and numeric parsing: the string is neither a recognized protocol name nor a parseable integer (ErrInvalidProtocolNumber). The message reminds the valid range 0-255.

Source

Thrown at hscontrol/policy/v2/types.go:1775

	case "", ProtocolNameICMP, ProtocolNameIGMP, ProtocolNameIPv4, ProtocolNameIPInIP,
		ProtocolNameTCP, ProtocolNameEGP, ProtocolNameIGP, ProtocolNameUDP, ProtocolNameGRE,
		ProtocolNameESP, ProtocolNameAH, ProtocolNameSCTP, ProtocolNameIPv6ICMP, ProtocolNameFC:
		return nil
	case ProtocolNameWildcard:
		// Wildcard "*" is not allowed - Tailscale rejects it
		return errUnknownProtocolWildcard
	default:
		// Try to parse as a numeric protocol number
		str := string(*p)

		// Check for leading zeros (not allowed by Tailscale)
		if str == "0" || (len(str) > 1 && str[0] == '0') {
			return fmt.Errorf("%w: %q", ErrProtocolLeadingZero, str)
		}

		protocolNumber, err := strconv.Atoi(str)
		if err != nil {
			return fmt.Errorf("%w: %q must be a known protocol name or valid protocol number 0-255", ErrInvalidProtocolNumber, *p)
		}

		if protocolNumber < 0 || protocolNumber > 255 {
			return fmt.Errorf("%w: %d", ErrProtocolOutOfRange, protocolNumber)
		}

		return nil
	}
}

// MarshalJSON implements JSON marshaling for [Protocol].
func (p *Protocol) MarshalJSON() ([]byte, error) {
	return json.Marshal(string(*p))
}

// Protocol constants matching the IANA numbers.
const (
	ProtocolICMP     = 1   // Internet Control Message

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use a known lowercase protocol name: tcp, udp, icmp, gre, esp, ah, sctp, etc.
  2. Or use a plain integer 1-255 without padding
  3. Trim whitespace and verify casing

Example fix

// before
{"proto": "TCP", "ports": [...]}
// after
{"proto": "tcp", "ports": [...]}
Defensive patterns

Strategy: validation

Validate before calling

var knownProtocols = map[string]bool{"tcp": true, "udp": true, "icmp": true, "gre": true, "esp": true, "ah": true, "sctp": true, "egp": true, "igp": true, "ipv6-icmp": true, "fc": true}

func validProtocol(s string) bool {
	s = strings.TrimSpace(s)
	if knownProtocols[s] { return true }
	_, err := strconv.Atoi(s)
	return err == nil && validProtocolNumber(s)
}

Prevention

When it happens

Trigger: A proto value like "htcp", "TCP " (trailing space), or any non-numeric unknown word. Note also that wildcard "*" reaches a dedicated earlier error, not this one.

Common situations: Typos in protocol names, casing errors (protocol names must be lowercase), or trailing whitespace from copy-paste.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/199d0a5cb9c21e5f. Report an issue: GitHub.