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

  1. Wrap the subchannel with OrcaOobUtil.OrcaHelper before use: create the subchannel via orcaHelper.newOrcaOobSubchannel(delegate) instead of creating it directly.
  2. In a custom LoadBalancer, pass all Subchannel creation through OrcaHelper.wrap() so ORCA reporting state is added to the subchannel attributes.
  3. Verify the subchannel's attributes contain the ORCA reporting state key before calling setListener (check attributes.get(ORCA_OOB_STATE_ATTR) != null).
  4. 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

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


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/c3343e8a544a95ba. Report an issue: GitHub.