{"record":{"id":"dcd83a3f25a6cb4c","repo":"istio/istio","slug":"delegate-http-route-cannot-contain-delegate","errorCode":null,"errorMessage":"delegate HTTP route cannot contain delegate","messagePattern":"delegate HTTP route cannot contain delegate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/validation/virtualservice.go","lineNumber":205,"sourceCode":"}\n\nfunc validateHTTPRouteConflict(http *networking.HTTPRoute, routeType HTTPRouteType) (errs error) {\n\tif routeType == RootRoute {\n\t\t// This is to check root conflict\n\t\t// only delegate can be specified\n\t\tif http.Redirect != nil {\n\t\t\terrs = appendErrors(errs, fmt.Errorf(\"root HTTP route %s must not specify redirect\", http.Name))\n\t\t}\n\t\tif http.Route != nil {\n\t\t\terrs = appendErrors(errs, fmt.Errorf(\"root HTTP route %s must not specify route\", http.Name))\n\t\t}\n\t\treturn errs\n\t}\n\n\t// This is to check delegate conflict\n\tif routeType == DelegateRoute {\n\t\tif http.Delegate != nil {\n\t\t\terrs = appendErrors(errs, errors.New(\"delegate HTTP route cannot contain delegate\"))\n\t\t}\n\t}\n\n\t// check for conflicts\n\tif http.Redirect != nil {\n\t\tif len(http.Route) > 0 {\n\t\t\terrs = appendErrors(errs, errors.New(\"HTTP route cannot contain both route and redirect\"))\n\t\t}\n\n\t\tif http.Fault != nil {\n\t\t\terrs = appendErrors(errs, errors.New(\"HTTP route cannot contain both fault and redirect\"))\n\t\t}\n\n\t\tif http.Rewrite != nil {\n\t\t\terrs = appendErrors(errs, errors.New(\"HTTP route rule cannot contain both rewrite and redirect\"))\n\t\t}\n\n\t\tif http.DirectResponse != nil {","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/istio/istio/blob/8dc789c5cf17517c64e3c36cb3288230f149dfae/pkg/config/validation/virtualservice.go#L187-L223","documentation":"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.","triggerScenarios":"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.","commonSituations":"Teams trying to build hierarchies of delegated VirtualServices (root -> team -> app) and attempting to chain delegation a second level deep.","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"],"exampleFix":"# before — child-vs (already delegated to) delegates again\nhttp:\n- match:\n  - {uri: {prefix: /foo}}\n  delegate: {name: leaf-vs, namespace: apps}\n\n# after — child-vs routes directly\nhttp:\n- match:\n  - {uri: {prefix: /foo/bar}}\n  route:\n  - destination: {host: foo-bar-svc}","handlingStrategy":"validation","validationCode":"// a route reached via delegation must not delegate again\nfunc delegateRoutesShallow(routes []*networking.HTTPRoute, isDelegateChild bool) bool {\n\tif !isDelegateChild {\n\t\treturn true\n\t}\n\tfor _, r := range routes {\n\t\tif r.GetDelegate() != nil {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":"func isNestedDelegate(route *networking.HTTPRoute, parentWasDelegated bool) bool {\n\treturn parentWasDelegated && route.GetDelegate() != nil\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["istio","virtualservice","delegation","routing","config-validation"],"backgroundTag":null,"analyzedSha":"8dc789c5cf17517c64e3c36cb3288230f149dfae","analyzedAt":"2026-08-15T15:16:55.434Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}