grpc/grpc-java · error · IllegalArgumentException
Subchannel does not have orca Out-Of-Band stream enabled. Tr
Error message
Subchannel does not have orca Out-Of-Band stream enabled. Try to use a subchannel created by OrcaOobUtil.OrcaHelper.
What it means
OrcaOobUtil.setListener() attaches an Out-of-Band ORCA (Open Request Cost Aggregation) load-report listener to a gRPC subchannel. It only works on subchannels created through OrcaOobUtil.OrcaHelper, which wrap the subchannel and register ORCA reporting state in its attributes. Passing a plain subchannel (no ORCA_OOB_STATE_ATTR attr) means there is no reporting state to attach the listener to, so an IllegalArgumentException is thrown immediately.
Source
Thrown at xds/src/main/java/io/grpc/xds/orca/OrcaOobUtil.java:210
*
* <p>If multiple load balancing policies configure reporting with different intervals, reports
* come with the minimum of those intervals.
*
* @param subchannel the server connected by this subchannel to receive the metrics.
*
* @param listener the callback upon receiving backend metrics from the Out-Of-Band stream.
* Setting to null to removes the listener from the subchannel.
*
* @param config the configuration to be set. It has no effect when listener is null.
*
*/
public static void setListener(Subchannel subchannel, OrcaOobReportListener listener,
OrcaReportingConfig config) {
Attributes attributes = subchannel.getAttributes();
SubchannelImpl orcaSubchannel =
(attributes == null) ? null : attributes.get(ORCA_REPORTING_STATE_KEY);
if (orcaSubchannel == null) {
throw new IllegalArgumentException("Subchannel does not have orca Out-Of-Band stream enabled."
+ " Try to use a subchannel created by OrcaOobUtil.OrcaHelper.");
}
orcaSubchannel.orcaState.setListener(orcaSubchannel, listener, config);
}
/**
* An {@link OrcaReportingHelper} wraps a delegated {@link LoadBalancer.Helper} with additional
* functionality to manage RPCs for out-of-band ORCA reporting for each backend it establishes
* connection to. Subchannels created through it will retrieve ORCA load reports if the server
* supports it.
*/
static final class OrcaReportingHelper extends ForwardingLoadBalancerHelper {
private final LoadBalancer.Helper delegate;
private final SynchronizationContext syncContext;
private final BackoffPolicy.Provider backoffPolicyProvider;
private final Supplier<Stopwatch> stopwatchSupplier;
OrcaReportingHelper(View on GitHub (pinned to 64daddc1f3)
Solutions
- Wrap the subchannel with OrcaOobUtil.OrcaHelper before use: create the subchannel via orcaHelper.newOrcaOobSubchannel(delegate) instead of creating it directly.
- In a custom LoadBalancer, pass all Subchannel creation through OrcaHelper.wrap() so ORCA reporting state is added to the subchannel attributes.
- Verify the subchannel's attributes contain the ORCA reporting state key before calling setListener (check attributes.get(ORCA_OOB_STATE_ATTR) != null).
- If ORCA load reporting is not needed, remove the setListener call instead of attaching a listener to plain subchannels.
Example fix
// before Subchannel subchannel = helper.createSubchannel(createArgs); OrcaOobUtil.setListener(subchannel, listener, config); // throws IllegalArgumentException // after OrcaOobUtil.OrcaHelper orcaHelper = OrcaOobUtil.newOrcaHelper(); Subchannel subchannel = orcaHelper.newOrcaOobSubchannel(createArgs); OrcaOobUtil.setListener(subchannel, listener, config);
Defensive patterns
Strategy: type-guard
Validate before calling
boolean orcaReady = subchannel.getAttributes() != null
&& subchannel.getAttributes().get(OrcaOobUtil.ORCA_OOB_STATE_ATTR) != null;
if (orcaReady) {
OrcaOobUtil.setListener(subchannel, listener, config);
} Type guard
static boolean isOrcaOobSubchannel(Subchannel sc) {
return sc != null && sc.getAttributes() != null
&& sc.getAttributes().get(OrcaOobUtil.ORCA_OOB_STATE_ATTR) != null;
} Try / catch
try {
OrcaOobUtil.setListener(subchannel, listener, config);
} catch (IllegalArgumentException e) {
logger.warn("Subchannel not ORCA-OOB-enabled; skipping listener attach", e);
} Prevention
- Always create subchannels via OrcaOobUtil.OrcaHelper.newOrcaOobSubchannel when ORCA reporting is planned.
- Check ORCA_OOB_STATE_ATTR in subchannel attributes before calling setListener.
- In custom LoadBalancers, route all subchannel creation through OrcaHelper.wrap/OrcaHelper consistently.
When it happens
Trigger: Calling OrcaOobUtil.setListener(subchannel, listener, config) with a Subchannel whose Attributes do not contain ORCA_OOB_REPORTING_STATE_KEY — i.e. a subchannel obtained directly from SubchannelFactory/LoadBalancer.Subchannel creation rather than from OrcaHelper.newOrcaOobSubchannel().
Common situations: Custom xDS/priority/round-robin load balancer implementations that intercept subchannel creation and forget to route it through OrcaHelper; upgrading grpc-xds and bypassing OrcaHelper when wiring custom pickers; manually constructing or delegating subchannels in a custom LoadBalancer and then attaching ORCA listeners.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid ring hash function: " + ringHash.getHashFunction()
- Invalid duration in weighted round robin config: " + ex.getM
- Cluster " + cluster.getName() + ": unsupported lb policy: "
- Cluster " + cluster.getName() + ": invalid ring hash functio
- Missing RingHash configuration
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/c3343e8a544a95ba.
Report an issue: GitHub.