{"record":{"id":"199d0a5cb9c21e5f","repo":"juanfont/headscale","slug":"w-q-must-be-a-known-protocol-name-or-valid-prot","errorCode":null,"errorMessage":"%w: %q must be a known protocol name or valid protocol number 0-255","messagePattern":"%w: %q must be a known protocol name or valid protocol number 0-255","errorType":"validation","errorClass":"ErrInvalidProtocolNumber","httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":1775,"sourceCode":"\tcase \"\", ProtocolNameICMP, ProtocolNameIGMP, ProtocolNameIPv4, ProtocolNameIPInIP,\n\t\tProtocolNameTCP, ProtocolNameEGP, ProtocolNameIGP, ProtocolNameUDP, ProtocolNameGRE,\n\t\tProtocolNameESP, ProtocolNameAH, ProtocolNameSCTP, ProtocolNameIPv6ICMP, ProtocolNameFC:\n\t\treturn nil\n\tcase ProtocolNameWildcard:\n\t\t// Wildcard \"*\" is not allowed - Tailscale rejects it\n\t\treturn errUnknownProtocolWildcard\n\tdefault:\n\t\t// Try to parse as a numeric protocol number\n\t\tstr := string(*p)\n\n\t\t// Check for leading zeros (not allowed by Tailscale)\n\t\tif str == \"0\" || (len(str) > 1 && str[0] == '0') {\n\t\t\treturn fmt.Errorf(\"%w: %q\", ErrProtocolLeadingZero, str)\n\t\t}\n\n\t\tprotocolNumber, err := strconv.Atoi(str)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%w: %q must be a known protocol name or valid protocol number 0-255\", ErrInvalidProtocolNumber, *p)\n\t\t}\n\n\t\tif protocolNumber < 0 || protocolNumber > 255 {\n\t\t\treturn fmt.Errorf(\"%w: %d\", ErrProtocolOutOfRange, protocolNumber)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// MarshalJSON implements JSON marshaling for [Protocol].\nfunc (p *Protocol) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(string(*p))\n}\n\n// Protocol constants matching the IANA numbers.\nconst (\n\tProtocolICMP     = 1   // Internet Control Message","sourceCodeStart":1757,"sourceCodeEnd":1793,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L1757-L1793","documentation":"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.","triggerScenarios":"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.","commonSituations":"Typos in protocol names, casing errors (protocol names must be lowercase), or trailing whitespace from copy-paste.","solutions":["Use a known lowercase protocol name: tcp, udp, icmp, gre, esp, ah, sctp, etc.","Or use a plain integer 1-255 without padding","Trim whitespace and verify casing"],"exampleFix":"// before\n{\"proto\": \"TCP\", \"ports\": [...]}\n// after\n{\"proto\": \"tcp\", \"ports\": [...]}","handlingStrategy":"validation","validationCode":"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}\n\nfunc validProtocol(s string) bool {\n\ts = strings.TrimSpace(s)\n\tif knownProtocols[s] { return true }\n\t_, err := strconv.Atoi(s)\n\treturn err == nil && validProtocolNumber(s)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use lowercase canonical protocol names","Trim whitespace around values copied from docs"],"tags":["policy","protocol","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}