grpc/grpc-go · error

OutlierDetectionLoadBalancingConfig.FailurePercentageEjectio…

Error message

OutlierDetectionLoadBalancingConfig.FailurePercentageEjection.threshold = %v; must be <= 100

What it means

Per gRFC A50, FailurePercentageEjection.threshold must be <= 100. ParseConfig checks lbCfg.FailurePercentageEjection != nil && Threshold > 100 (balancer.go:146-147) and rejects. Threshold sets the failure-rate percentage above which an endpoint is considered for ejection.

Solutions

  1. Set FailurePercentageEjection.Threshold to a value in [0, 100].
  2. Validate the percentage range before constructing the config.

Example fix

// before
cfg.FailurePercentageEjection = &outlierdetection.FailurePercentageEjection{Threshold: 150}
// after
cfg.FailurePercentageEjection = &outlierdetection.FailurePercentageEjection{Threshold: 80}
Defensive patterns

Strategy: validation

Validate before calling

func validateFailurePercentageThreshold(fpe *outlierdetection.FailurePercentageEjection) error {
    if fpe != nil && fpe.Threshold > 100 {
        return fmt.Errorf("failure_percentage.threshold must be <= 100, got %d", fpe.Threshold)
    }
    return nil
}

Prevention

When it happens

Trigger: FailurePercentageEjection is set in the config and its Threshold field exceeds 100.

Common situations: Manual config with threshold > 100; typo; control plane misconfiguration.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/0bf70fa7e74bcd5c. Report an issue: GitHub.

Appendix: source

Thrown at internal/xds/balancer/outlierdetection/balancer.go:147

	// within +-10000 years. Thus, just check for negative values.
	case lbCfg.Interval < 0:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.interval = %s; must be >= 0", lbCfg.Interval)
	case lbCfg.BaseEjectionTime < 0:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.base_ejection_time = %s; must be >= 0", lbCfg.BaseEjectionTime)
	case lbCfg.MaxEjectionTime < 0:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.max_ejection_time = %s; must be >= 0", lbCfg.MaxEjectionTime)

	// "The fields max_ejection_percent,
	// success_rate_ejection.enforcement_percentage,
	// failure_percentage_ejection.threshold, and
	// failure_percentage.enforcement_percentage must have values less than or
	// equal to 100." - A50
	case lbCfg.MaxEjectionPercent > 100:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.max_ejection_percent = %v; must be <= 100", lbCfg.MaxEjectionPercent)
	case lbCfg.SuccessRateEjection != nil && lbCfg.SuccessRateEjection.EnforcementPercentage > 100:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.SuccessRateEjection.enforcement_percentage = %v; must be <= 100", lbCfg.SuccessRateEjection.EnforcementPercentage)
	case lbCfg.FailurePercentageEjection != nil && lbCfg.FailurePercentageEjection.Threshold > 100:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.FailurePercentageEjection.threshold = %v; must be <= 100", lbCfg.FailurePercentageEjection.Threshold)
	case lbCfg.FailurePercentageEjection != nil && lbCfg.FailurePercentageEjection.EnforcementPercentage > 100:
		return nil, fmt.Errorf("OutlierDetectionLoadBalancingConfig.FailurePercentageEjection.enforcement_percentage = %v; must be <= 100", lbCfg.FailurePercentageEjection.EnforcementPercentage)
	}
	return lbCfg, nil
}

func (bb) Name() string {
	return Name
}

// scUpdate wraps a subConn update to be sent to the child balancer.
type scUpdate struct {
	scw   *subConnWrapper
	state balancer.SubConnState
}

type ejectionUpdate struct {
	scw       *subConnWrapper

View on GitHub (pinned to 0c51461d27)