{"record":{"id":"d52c43fe050ec27d","repo":"istio/istio","slug":"http-route-cannot-contain-both-fault-and-redirect","errorCode":null,"errorMessage":"HTTP route cannot contain both fault and redirect","messagePattern":"HTTP route cannot contain both fault and redirect","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/validation/virtualservice.go","lineNumber":216,"sourceCode":"\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 {\n\t\t\terrs = appendErrors(errs, errors.New(\"HTTP route rule cannot contain both direct_response and redirect\"))\n\t\t}\n\t} else if http.DirectResponse != nil {\n\t\tif len(http.Route) > 0 {\n\t\t\terrs = appendErrors(errs, errors.New(\"HTTP route cannot contain both route and direct_response\"))\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 direct_response\"))\n\t\t}\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/istio/istio/blob/8dc789c5cf17517c64e3c36cb3288230f149dfae/pkg/config/validation/virtualservice.go#L198-L234","documentation":"Fault injection ('fault') is a traffic-policy action applied to forwarded traffic; it cannot coexist with 'redirect' on the same http route, because a redirected request never reaches the proxy forwarding path where faults are injected. Validation rejects the combination outright.","triggerScenarios":"An http route with both 'fault:' (delay/abort) and 'redirect:' set.","commonSituations":"Reusing a chaos-testing route template and adding a redirect; moving routes around during refactors leaving both blocks.","solutions":["Remove 'fault' from the redirecting route","If you need faults plus redirect-like behavior, apply faults on the destination route in the target service instead","Split into separate matched routes if different paths need different behaviors"],"exampleFix":"# before\nhttp:\n- match: [{uri: {prefix: /old}}]\n  fault:\n    abort: {httpStatus: 500, percentage: {value: 100}}\n  redirect: {uri: /new}\n\n# after\nhttp:\n- match: [{uri: {prefix: /old}}]\n  redirect: {uri: /new}","handlingStrategy":"validation","validationCode":"func faultAndRedirectCompatible(http *networking.HTTPRoute) bool {\n\treturn !(http.GetFault() != nil && http.GetRedirect() != nil)\n}","typeGuard":"func hasFaultRedirectConflict(http *networking.HTTPRoute) bool {\n\treturn http.GetFault() != nil && http.GetRedirect() != nil\n}","tryCatchPattern":null,"preventionTips":["Faults only attach to forwarding routes; strip them when converting a route to a redirect","Keep chaos-engineering routes in separate manifests so they are not merged into redirect rules"],"tags":["istio","virtualservice","fault-injection","redirect","conflict"],"backgroundTag":null,"analyzedSha":"8dc789c5cf17517c64e3c36cb3288230f149dfae","analyzedAt":"2026-08-15T15:16:55.434Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}