istio/istio · error
delegate HTTP route cannot contain delegate
Error message
delegate HTTP route cannot contain delegate
What it means
In Istio's delegated VirtualService routing, a route that is itself the target of a delegation (routeType == DelegateRoute) must not contain another 'delegate' stanza. Nested delegation would create ambiguous, possibly recursive route resolution, so one level of delegation is enforced.
Source
Thrown at pkg/config/validation/virtualservice.go:205
}
func validateHTTPRouteConflict(http *networking.HTTPRoute, routeType HTTPRouteType) (errs error) {
if routeType == RootRoute {
// This is to check root conflict
// only delegate can be specified
if http.Redirect != nil {
errs = appendErrors(errs, fmt.Errorf("root HTTP route %s must not specify redirect", http.Name))
}
if http.Route != nil {
errs = appendErrors(errs, fmt.Errorf("root HTTP route %s must not specify route", http.Name))
}
return errs
}
// This is to check delegate conflict
if routeType == DelegateRoute {
if http.Delegate != nil {
errs = appendErrors(errs, errors.New("delegate HTTP route cannot contain delegate"))
}
}
// check for conflicts
if http.Redirect != nil {
if len(http.Route) > 0 {
errs = appendErrors(errs, errors.New("HTTP route cannot contain both route and redirect"))
}
if http.Fault != nil {
errs = appendErrors(errs, errors.New("HTTP route cannot contain both fault and redirect"))
}
if http.Rewrite != nil {
errs = appendErrors(errs, errors.New("HTTP route rule cannot contain both rewrite and redirect"))
}
if http.DirectResponse != nil {View on GitHub (pinned to 8dc789c5cf)
Solutions
- Flatten to one delegation level: the root delegates directly to each leaf VirtualService
- Use match prefixes on the root to send different paths to different leaf VSs instead of chaining
- Move the second-level 'delegate' route's matching logic into the leaf VS's own route rules
Example fix
# before — child-vs (already delegated to) delegates again
http:
- match:
- {uri: {prefix: /foo}}
delegate: {name: leaf-vs, namespace: apps}
# after — child-vs routes directly
http:
- match:
- {uri: {prefix: /foo/bar}}
route:
- destination: {host: foo-bar-svc} Defensive patterns
Strategy: validation
Validate before calling
// a route reached via delegation must not delegate again
func delegateRoutesShallow(routes []*networking.HTTPRoute, isDelegateChild bool) bool {
if !isDelegateChild {
return true
}
for _, r := range routes {
if r.GetDelegate() != nil {
return false
}
}
return true
} Type guard
func isNestedDelegate(route *networking.HTTPRoute, parentWasDelegated bool) bool {
return parentWasDelegated && route.GetDelegate() != nil
} Prevention
- Design delegation as a single level: root VS delegates directly to leaf VSs
- Document which VirtualServices are roots vs leaves to prevent teams from chaining
When it happens
Trigger: A child VirtualService matched via a delegate root that itself declares 'delegate:' on one of its http routes — i.e., chaining root VS -> delegate VS -> another delegate VS.
Common situations: Teams trying to build hierarchies of delegated VirtualServices (root -> team -> app) and attempting to chain delegation a second level deep.
Related errors
- JWT claim based routing (key: %s) is only supported for gate
- http, tcp or tls must be provided in virtual service
- TLS route must have at least one match condition
- TLS route is required
- TCP route is required
AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15).
Data as JSON: /api/errors/dcd83a3f25a6cb4c.
Report an issue: GitHub.