{"record":{"id":"48a3c8a235ea0de1","repo":"istio/istio","slug":"protocol-q-is-unsupported-hint-q-uppercase-m","errorCode":null,"errorMessage":"protocol %q is unsupported. hint: %q (uppercase) may be supported","messagePattern":"protocol %q is unsupported\\. hint: %q \\(uppercase\\) may be supported","errorType":"validation","errorClass":"ListenerStatusConfigError","httpStatus":null,"severity":"error","filePath":"pilot/pkg/config/kube/agentgateway/listener.go","lineNumber":207,"sourceCode":"\t\treturn string(p), nil\n\tcase gatewayv1.TLSProtocolType:\n\t\treturn string(p), nil\n\tcase gatewayv1.TCPProtocolType:\n\t\tif !features.EnableAlphaGatewayAPI {\n\t\t\treturn \"\", fmt.Errorf(\"protocol %q is only supported when the alpha Gateway API is enabled\", p)\n\t\t}\n\t\treturn string(p), nil\n\t// Our own custom types\n\tcase gatewayv1.ProtocolType(protocol.HBONE):\n\t\tif name != constants.ManagedGatewayMeshController && name != constants.ManagedGatewayEastWestController &&\n\t\t\tname != constants.ManagedAgentgatewayWaypointController && name != constants.ManagedAgentgatewayController {\n\t\t\treturn \"\", fmt.Errorf(\"protocol %q is only supported for HBONE-enabled gateways/waypoints\", p)\n\t\t}\n\t\treturn string(p), nil\n\t}\n\tup := gatewayv1.ProtocolType(strings.ToUpper(string(p)))\n\tif supportedProtocols.Contains(up) {\n\t\treturn \"\", fmt.Errorf(\"protocol %q is unsupported. hint: %q (uppercase) may be supported\", p, up)\n\t}\n\t// Note: the gatewayv1.UDPProtocolType is explicitly left to hit this path\n\treturn \"\", fmt.Errorf(\"protocol %q is unsupported\", p)\n}\n\n// Same as buildHostnameMatch in gateway/conversion.go\n// buildHostnameMatch generates a Gateway.spec.servers.hosts section from a listener\nfunc buildHostnameMatch(ctx krt.HandlerContext, localNamespace string, namespaces krt.Collection[*corev1.Namespace], l gatewayv1.Listener) []string {\n\t// We may allow all hostnames or a specific one\n\thostname := \"*\"\n\tif l.Hostname != nil {\n\t\thostname = string(*l.Hostname)\n\t}\n\n\tresp := []string{}\n\tfor _, ns := range namespacesFromSelector(ctx, localNamespace, namespaces, l.AllowedRoutes) {\n\t\t// This check is necessary to prevent adding a hostname with an invalid empty namespace\n\t\tif len(ns) > 0 {","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/istio/istio/blob/8dc789c5cf17517c64e3c36cb3288230f149dfae/pilot/pkg/config/kube/agentgateway/listener.go#L189-L225","documentation":"listenerProtocolToIstio matches listener protocols case-sensitively against the supportedProtocols set ({HTTP, HTTPS, TLS, TCP, HBONE}, see listener.go:50-55). If the exact string is not in the set but its UPPERCASE form is, this error is returned with a hint naming the capitalized value. It exists to catch casing mistakes like 'http' instead of 'HTTP' rather than silently accepting or rejecting them.","triggerScenarios":"A Gateway listener with protocol written as http, https, tls, tcp (lowercase) or mixed case such as Http. The Gateway API CRD enum normally blocks these, so this is typically hit when objects are constructed programmatically, applied with relaxed/older CRDs, or transformed by templating tools that lowercase strings.","commonSituations":"Helm/kustomize string transformations lowercasing protocol fields; config generated from code or data files without enum validation; hand-edited manifests; CI that bypasses server-side CRD validation.","solutions":["Rewrite the protocol exactly as shown in the hint (e.g., 'http' -> 'HTTP')","Lint manifests against the gateway.networking.k8s.io CRDs so enum/case violations are caught at apply time (kubectl apply --dry-run=server)","Fix the templating/tooling that is altering the casing of the protocol field"],"exampleFix":"# before\nspec:\n  listeners:\n  - name: http\n    port: 80\n    protocol: http\n# after\nspec:\n  listeners:\n  - name: http\n    port: 80\n    protocol: HTTP","handlingStrategy":"validation","validationCode":"canonical := sets.New(\n    string(gatewayv1.HTTPProtocolType),\n    string(gatewayv1.HTTPSProtocolType),\n    string(gatewayv1.TLSProtocolType),\n    string(gatewayv1.TCPProtocolType),\n    string(gatewayv1.ProtocolType(protocol.HBONE)),\n)\nfor _, l := range gw.Spec.Listeners {\n    if !canonical.Contains(string(l.Protocol)) {\n        up := strings.ToUpper(string(l.Protocol))\n        if canonical.Contains(up) {\n            return fmt.Errorf(\"listener %q: protocol %q must be written %q\", l.Name, l.Protocol, up)\n        }\n        return fmt.Errorf(\"listener %q: unsupported protocol %q\", l.Name, l.Protocol)\n    }\n}","typeGuard":"func hasCanonicalProtocol(l gatewayv1.Listener) bool {\n    switch string(l.Protocol) {\n    case \"HTTP\", \"HTTPS\", \"TLS\", \"TCP\", \"HBONE\":\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Generate Gateway manifests from typed structs (sigsgatewayv1) instead of string templates so enums enforce casing","Apply with server-side dry-run so the CRD enum rejects lowercase protocols at admission","Add a lint rule (yamllint regex or conftest) requiring protocol to match ^(HTTP|HTTPS|TLS|TCP|HBONE)$"],"tags":["istio","gateway-api","protocol","case-sensitivity","agentgateway"],"backgroundTag":null,"analyzedSha":"8dc789c5cf17517c64e3c36cb3288230f149dfae","analyzedAt":"2026-08-15T15:16:55.434Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}