istio/istio · error

HTTP route cannot contain both fault and redirect

Error message

HTTP route cannot contain both fault and redirect

What it means

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.

Source

Thrown at pkg/config/validation/virtualservice.go:216

		}
		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 {
			errs = appendErrors(errs, errors.New("HTTP route rule cannot contain both direct_response and redirect"))
		}
	} else if http.DirectResponse != nil {
		if len(http.Route) > 0 {
			errs = appendErrors(errs, errors.New("HTTP route cannot contain both route and direct_response"))
		}

		if http.Fault != nil {
			errs = appendErrors(errs, errors.New("HTTP route cannot contain both fault and direct_response"))
		}

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Remove 'fault' from the redirecting route
  2. If you need faults plus redirect-like behavior, apply faults on the destination route in the target service instead
  3. Split into separate matched routes if different paths need different behaviors

Example fix

# before
http:
- match: [{uri: {prefix: /old}}]
  fault:
    abort: {httpStatus: 500, percentage: {value: 100}}
  redirect: {uri: /new}

# after
http:
- match: [{uri: {prefix: /old}}]
  redirect: {uri: /new}
Defensive patterns

Strategy: validation

Validate before calling

func faultAndRedirectCompatible(http *networking.HTTPRoute) bool {
	return !(http.GetFault() != nil && http.GetRedirect() != nil)
}

Type guard

func hasFaultRedirectConflict(http *networking.HTTPRoute) bool {
	return http.GetFault() != nil && http.GetRedirect() != nil
}

Prevention

When it happens

Trigger: An http route with both 'fault:' (delay/abort) and 'redirect:' set.

Common situations: Reusing a chaos-testing route template and adding a redirect; moving routes around during refactors leaving both blocks.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/d52c43fe050ec27d. Report an issue: GitHub.