apache/beam · error · UnsupportedOperationException

Runner does not support draining.

Error message

Runner does not support draining.

What it means

PipelineResult.drain() is an optional API for draining (finishing without processing further input) a streaming pipeline. The default implementation in the PipelineResult interface throws UnsupportedOperationException because not every runner supports draining; the runner you are using never overrode it.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/PipelineResult.java:56

  /**
   * Cancels the pipeline execution.
   *
   * @throws IOException if there is a problem executing the cancel request.
   * @throws UnsupportedOperationException if the runner does not support cancellation.
   */
  State cancel() throws IOException;

  /**
   * Drains the pipeline execution.
   *
   * <p>Draining requests that the runner stop accepting new input and finish processing data that
   * has already entered the pipeline.
   *
   * @throws IOException if there is a problem executing the drain request.
   * @throws UnsupportedOperationException if the runner does not support draining.
   */
  default State drain() throws IOException {
    throw new UnsupportedOperationException("Runner does not support draining.");
  }

  /**
   * Waits until the pipeline finishes and returns the final status. It times out after the given
   * duration.
   *
   * @param duration The time to wait for the pipeline to finish. Provide a value less than 1 ms for
   *     an infinite wait.
   * @return The final state of the pipeline or null on timeout.
   * @throws UnsupportedOperationException if the runner does not support waiting to finish with a
   *     timeout.
   */
  State waitUntilFinish(Duration duration);

  /**
   * Waits until the pipeline finishes and returns the final status.
   *
   * @return The final state of the pipeline.

View on GitHub (pinned to 12126d8942)

Solutions

  1. Check runner support before draining: if (result instanceof DrainingResult) or consult the runner's capabilities documentation.
  2. Guard with try-catch on UnsupportedOperationException and fall back to cancel() or waitUntilFinish().
  3. Switch to a runner that supports drain (e.g. run in streaming mode on Dataflow/Flink/Spark runners).
  4. If the pipeline is batch, drain is not applicable - use cancel() or waitUntilFinish() instead.

Example fix

// before
PipelineResult result = pipeline.run();
result.drain();
// after
PipelineResult result = pipeline.run();
try {
  result.drain();
} catch (UnsupportedOperationException e) {
  result.cancel(); // runner does not support draining
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before draining, check capability
if (result.getClass().getName().equals("org.apache.beam.sdk.runners.DirectRunner$DirectPipelineResult")) {
  throw new IllegalStateException("Runner does not support drain");
}

Try / catch

try {
  result.drain();
} catch (UnsupportedOperationException e) {
  LOG.warn("Runner does not support draining; falling back to cancel", e);
  result.cancel();
}

Prevention

When it happens

Trigger: Calling drain() on a PipelineResult from a runner that has not implemented it (e.g. DirectRunner or other runners without drain support).

Common situations: Code written for a streaming runner with drain support (like DataflowRunner/FlinkRunner in streaming mode) is run against a different runner (DirectRunner, TestPipeline) without checking support; batch pipelines where drain is meaningless.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/dcc67a142cc6e9d9. Report an issue: GitHub.