istio/istio · error
JWT claim based routing (key: %s) is only supported for gate
Error message
JWT claim based routing (key: %s) is only supported for gateway, found no gateways: %v
What it means
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.
Source
Thrown at pkg/config/validation/validation.go:1782
}
gatewaySemantics := cfg.Annotations[constants.InternalRouteSemantics] == constants.RouteSemanticsGateway
appliesToMesh := false
appliesToGateway := false
if len(virtualService.Gateways) == 0 {
appliesToMesh = true
} else {
errs = AppendValidation(errs, validateGatewayNames(virtualService.Gateways, gatewaySemantics))
appliesToGateway = isGateway(virtualService)
appliesToMesh = !appliesToGateway
}
if !appliesToGateway {
validateJWTClaimRoute := func(headers map[string]*networking.StringMatch) {
for key := range headers {
if jwt.ToRoutingClaim(key).Match {
msg := fmt.Sprintf("JWT claim based routing (key: %s) is only supported for gateway, found no gateways: %v", key, virtualService.Gateways)
errs = AppendValidation(errs, errors.New(msg))
}
}
}
for _, http := range virtualService.GetHttp() {
for _, m := range http.GetMatch() {
validateJWTClaimRoute(m.GetHeaders())
validateJWTClaimRoute(m.GetWithoutHeaders())
}
}
}
allHostsValid := true
for _, virtualHost := range virtualService.Hosts {
var err error
if appliesToGateway {
err = agent.ValidateWildcardDomainForVirtualServiceBoundToGateway(isSniHost(virtualService), virtualHost)
} else {
err = agent.ValidateWildcardDomain(virtualHost)View on GitHub (pinned to 8dc789c5cf)
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
Example fix
# before
kind: VirtualService
spec:
gateways: ["mesh"]
http:
- match:
- headers:
request.auth.claims/roles: { exact: "admin" }
# after
kind: VirtualService
spec:
gateways: ["istio-system/my-gateway"]
hosts: ["api.example.com"]
http:
- match:
- headers:
request.auth.claims/roles: { exact: "admin" } Defensive patterns
Strategy: validation
Validate before calling
func usesJWTClaimKey(h map[string]*StringMatch) bool {
for k := range h {
if strings.HasPrefix(k, "request.auth.claims/") || strings.HasPrefix(k, "request.audiences") || strings.HasPrefix(k, "request.auth.presenter") || strings.HasPrefix(k, "request.auth.principal") {
return true
}
}
return false
}
func checkClaimRoutingNeedsGateway(vs *VirtualService) error {
for _, h := range vs.HTTP {
for _, m := range h.Match {
if (usesJWTClaimKey(m.Headers) || usesJWTClaimKey(m.WithoutHeaders)) && len(vs.Gateways) == 0 {
return errors.New("JWT claim routing requires a gateway; add spec.gateways")
}
}
}
return nil
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- TLS route must have at least one match condition
- TLS route is required
- TCP route is required
- delegate HTTP route cannot contain delegate
- HTTP route cannot contain both route and redirect
AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15).
Data as JSON: /api/errors/3649783423c6572f.
Report an issue: GitHub.