{"record":{"id":"c3343e8a544a95ba","repo":"grpc/grpc-java","slug":"subchannel-does-not-have-orca-out-of-band-stream-e","errorCode":null,"errorMessage":"Subchannel does not have orca Out-Of-Band stream enabled. Try to use a subchannel created by OrcaOobUtil.OrcaHelper.","messagePattern":"Subchannel does not have orca Out-Of-Band stream enabled\\. Try to use a subchannel created by OrcaOobUtil\\.OrcaHelper\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/orca/OrcaOobUtil.java","lineNumber":210,"sourceCode":"   *\n   * <p>If multiple load balancing policies configure reporting with different intervals, reports\n   * come with the minimum of those intervals.\n   *\n   * @param subchannel the server connected by this subchannel to receive the metrics.\n   *\n   * @param listener the callback upon receiving backend metrics from the Out-Of-Band stream.\n   *                 Setting to null to removes the listener from the subchannel.\n   *\n   * @param config the configuration to be set. It has no effect when listener is null.\n   *\n   */\n  public static void setListener(Subchannel subchannel, OrcaOobReportListener listener,\n                                 OrcaReportingConfig config) {\n    Attributes attributes = subchannel.getAttributes();\n    SubchannelImpl orcaSubchannel =\n        (attributes == null) ? null : attributes.get(ORCA_REPORTING_STATE_KEY);\n    if (orcaSubchannel == null) {\n      throw new IllegalArgumentException(\"Subchannel does not have orca Out-Of-Band stream enabled.\"\n          + \" Try to use a subchannel created by OrcaOobUtil.OrcaHelper.\");\n    }\n    orcaSubchannel.orcaState.setListener(orcaSubchannel, listener, config);\n  }\n\n  /**\n   * An {@link OrcaReportingHelper} wraps a delegated {@link LoadBalancer.Helper} with additional\n   * functionality to manage RPCs for out-of-band ORCA reporting for each backend it establishes\n   * connection to. Subchannels created through it will retrieve ORCA load reports if the server\n   * supports it.\n   */\n  static final class OrcaReportingHelper extends ForwardingLoadBalancerHelper {\n    private final LoadBalancer.Helper delegate;\n    private final SynchronizationContext syncContext;\n    private final BackoffPolicy.Provider backoffPolicyProvider;\n    private final Supplier<Stopwatch> stopwatchSupplier;\n\n    OrcaReportingHelper(","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/orca/OrcaOobUtil.java#L192-L228","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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."],"exampleFix":"// before\nSubchannel subchannel = helper.createSubchannel(createArgs);\nOrcaOobUtil.setListener(subchannel, listener, config); // throws IllegalArgumentException\n\n// after\nOrcaOobUtil.OrcaHelper orcaHelper = OrcaOobUtil.newOrcaHelper();\nSubchannel subchannel = orcaHelper.newOrcaOobSubchannel(createArgs);\nOrcaOobUtil.setListener(subchannel, listener, config);","handlingStrategy":"type-guard","validationCode":"boolean orcaReady = subchannel.getAttributes() != null\n    && subchannel.getAttributes().get(OrcaOobUtil.ORCA_OOB_STATE_ATTR) != null;\nif (orcaReady) {\n  OrcaOobUtil.setListener(subchannel, listener, config);\n}","typeGuard":"static boolean isOrcaOobSubchannel(Subchannel sc) {\n  return sc != null && sc.getAttributes() != null\n      && sc.getAttributes().get(OrcaOobUtil.ORCA_OOB_STATE_ATTR) != null;\n}","tryCatchPattern":"try {\n  OrcaOobUtil.setListener(subchannel, listener, config);\n} catch (IllegalArgumentException e) {\n  logger.warn(\"Subchannel not ORCA-OOB-enabled; skipping listener attach\", e);\n}","preventionTips":["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."],"tags":["grpc","xds","orca","load-balancing","illegal-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}