{"record":{"id":"3649783423c6572f","repo":"istio/istio","slug":"jwt-claim-based-routing-key-s-is-only-supporte","errorCode":null,"errorMessage":"JWT claim based routing (key: %s) is only supported for gateway, found no gateways: %v","messagePattern":"JWT claim based routing \\(key: (.+?)\\) is only supported for gateway, found no gateways: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/validation/validation.go","lineNumber":1782,"sourceCode":"\t\t}\n\t\tgatewaySemantics := cfg.Annotations[constants.InternalRouteSemantics] == constants.RouteSemanticsGateway\n\n\t\tappliesToMesh := false\n\t\tappliesToGateway := false\n\t\tif len(virtualService.Gateways) == 0 {\n\t\t\tappliesToMesh = true\n\t\t} else {\n\t\t\terrs = AppendValidation(errs, validateGatewayNames(virtualService.Gateways, gatewaySemantics))\n\t\t\tappliesToGateway = isGateway(virtualService)\n\t\t\tappliesToMesh = !appliesToGateway\n\t\t}\n\n\t\tif !appliesToGateway {\n\t\t\tvalidateJWTClaimRoute := func(headers map[string]*networking.StringMatch) {\n\t\t\t\tfor key := range headers {\n\t\t\t\t\tif jwt.ToRoutingClaim(key).Match {\n\t\t\t\t\t\tmsg := fmt.Sprintf(\"JWT claim based routing (key: %s) is only supported for gateway, found no gateways: %v\", key, virtualService.Gateways)\n\t\t\t\t\t\terrs = AppendValidation(errs, errors.New(msg))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, http := range virtualService.GetHttp() {\n\t\t\t\tfor _, m := range http.GetMatch() {\n\t\t\t\t\tvalidateJWTClaimRoute(m.GetHeaders())\n\t\t\t\t\tvalidateJWTClaimRoute(m.GetWithoutHeaders())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tallHostsValid := true\n\t\tfor _, virtualHost := range virtualService.Hosts {\n\t\t\tvar err error\n\t\t\tif appliesToGateway {\n\t\t\t\terr = agent.ValidateWildcardDomainForVirtualServiceBoundToGateway(isSniHost(virtualService), virtualHost)\n\t\t\t} else {\n\t\t\t\terr = agent.ValidateWildcardDomain(virtualHost)","sourceCodeStart":1764,"sourceCodeEnd":1800,"githubUrl":"https://github.com/istio/istio/blob/8dc789c5cf17517c64e3c36cb3288230f149dfae/pkg/config/validation/validation.go#L1764-L1800","documentation":"Istio only supports JWT claim based routing (header match keys recognized by jwt.ToRoutingClaim, e.g. 'request.auth.claims.foo' or 'request.audiences') on routes bound to a gateway. This error fires when a VirtualService that applies only to the mesh (no gateway, or gateways resolving to mesh semantics) uses such a claim key in match.headers or match.withoutHeaders.","triggerScenarios":"A VirtualService with gateways: [\"mesh\"] (or no gateways at all) whose HTTPMatchRequest headers/withoutHeaders map contains a JWT routing claim key like request.auth.claims/roles.","commonSituations":"Reusing a gateway-oriented VirtualService in a sidecar/mesh-only setup; explicitly setting gateways to [\"mesh\"] while keeping claim-based match keys; assuming claim routing works for east-west traffic.","solutions":["Attach the VirtualService to a real gateway, e.g. gateways: [\"my-gateway-ns/my-gateway\"]","Remove the JWT claim match keys from headers/withoutHeaders for mesh-internal routing and use plain header or destination-based matching instead","Verify gateway names with istioctl proxy-config or kubectl get gateway"],"exampleFix":"# before\nkind: VirtualService\nspec:\n  gateways: [\"mesh\"]\n  http:\n    - match:\n        - headers:\n            request.auth.claims/roles: { exact: \"admin\" }\n# after\nkind: VirtualService\nspec:\n  gateways: [\"istio-system/my-gateway\"]\n  hosts: [\"api.example.com\"]\n  http:\n    - match:\n        - headers:\n            request.auth.claims/roles: { exact: \"admin\" }","handlingStrategy":"validation","validationCode":"func usesJWTClaimKey(h map[string]*StringMatch) bool {\n\tfor k := range h {\n\t\tif strings.HasPrefix(k, \"request.auth.claims/\") || strings.HasPrefix(k, \"request.audiences\") || strings.HasPrefix(k, \"request.auth.presenter\") || strings.HasPrefix(k, \"request.auth.principal\") {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc checkClaimRoutingNeedsGateway(vs *VirtualService) error {\n\tfor _, h := range vs.HTTP {\n\t\tfor _, m := range h.Match {\n\t\t\tif (usesJWTClaimKey(m.Headers) || usesJWTClaimKey(m.WithoutHeaders)) && len(vs.Gateways) == 0 {\n\t\t\t\treturn errors.New(\"JWT claim routing requires a gateway; add spec.gateways\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reserve request.auth.* header keys for gateway-bound VirtualServices only","Lint VirtualServices in CI to reject claim keys when gateways includes 'mesh' or is absent"],"tags":["istio","virtualservice","jwt","routing"],"backgroundTag":null,"analyzedSha":"8dc789c5cf17517c64e3c36cb3288230f149dfae","analyzedAt":"2026-08-15T15:16:55.434Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}