grpc/grpc-go · error
OutlierDetectionLoadBalancingConfig.SuccessRateEjection.enfo…
Error message
OutlierDetectionLoadBalancingConfig.SuccessRateEjection.enforcement_percentage = %v; must be <= 100
What it means
Per gRFC A50, SuccessRateEjection.enforcement_percentage must be <= 100. ParseConfig checks lbCfg.SuccessRateEjection != nil && EnforcementPercentage > 100 (balancer.go:144-145) and rejects. The field controls the probability of enforcing a success-rate ejection.
Solutions
- Set SuccessRateEjection.EnforcementPercentage to a value in [0, 100].
- Validate the percentage range before constructing the config.
Example fix
// before
cfg.SuccessRateEjection = &outlierdetection.SuccessRateEjection{EnforcementPercentage: 150}
// after
cfg.SuccessRateEjection = &outlierdetection.SuccessRateEjection{EnforcementPercentage: 100} Defensive patterns
Strategy: validation
Validate before calling
func validateSuccessRateEnforcement(sre *outlierdetection.SuccessRateEjection) error {
if sre != nil && sre.EnforcementPercentage > 100 {
return fmt.Errorf("success_rate.enforcement_percentage must be <= 100, got %d", sre.EnforcementPercentage)
}
return nil
} Prevention
- When setting SuccessRateEjection, default EnforcementPercentage to a value <= 100 (A50 default 0).
- Range-check the nested struct before assigning it to LBConfig.
- Add a unit test that asserts nested percentages stay in range.
When it happens
Trigger: SuccessRateEjection is set in the config and its EnforcementPercentage field exceeds 100.
Common situations: Manual config with enforcement_percentage > 100; typo; control plane misconfiguration.
Related errors
- OutlierDetectionLoadBalancingConfig.FailurePercentageEjectio…
- OutlierDetectionLoadBalancingConfig.FailurePercentageEjectio…
- OutlierDetectionLoadBalancingConfig.max_ejection_percent =
- OutlierDetectionLoadBalancingConfig.base_ejection_time =
- OutlierDetectionLoadBalancingConfig.interval =
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/47cfcbc30f05c061.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/balancer/outlierdetection/balancer.go:145
// Approximately 290 years is the maximum time that time.Duration (int64)
// can represent. The restrictions on the protobuf.Duration field are to be
// 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
}
View on GitHub (pinned to 0c51461d27)