apache/beam · error · IllegalStateException

PipelineOptions not set

Error message

PipelineOptions not set

What it means

The FinishBundle-time argument provider exposes PipelineOptions to @FinishBundle methods; the options field is injected by the runner before invocation. If it is still null when pipelineOptions() is called, the wrapper throws IllegalStateException. This means the context object was used outside a runner-driven FinishBundle invocation.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/AsyncWrapper.java:401

      BoundedWindow window,
      Instant timestamp,
      OutputReceiver<OutputT> receiver) {
    return new ProcessArgProvider(element, window, timestamp, receiver);
  }

  // Named BaseArgumentProvider supplying bundle-level lifecycle context to the invoker.
  private class BundleArgProvider extends DoFnInvoker.BaseArgumentProvider<InputT, OutputT> {
    private final AccumulatingOutputReceiver<OutputT> receiver;

    BundleArgProvider(AccumulatingOutputReceiver<OutputT> receiver) {
      this.receiver = receiver;
    }

    @Override
    public PipelineOptions pipelineOptions() {
      PipelineOptions options = pipelineOptions;
      if (options == null) {
        throw new IllegalStateException("PipelineOptions not set");
      }
      return options;
    }

    @Override
    public DoFn<InputT, OutputT>.FinishBundleContext finishBundleContext(
        DoFn<InputT, OutputT> doFn) {
      return new AsyncFinishBundleContext(doFn, receiver);
    }

    @Override
    public String getErrorContext() {
      return "AsyncWrapper/Bundle";
    }
  }

  // FinishBundleContext subclass bound to the enclosing DoFn instance to prevent compiler crashes.
  private class AsyncFinishBundleContext extends DoFn<InputT, OutputT>.FinishBundleContext {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Run the DoFn through a real runner or TestPipeline so options are injected before FinishBundle
  2. In tests, use DoFnTester with a context that provides PipelineOptions (e.g. PipelineOptionsFactory.create())
  3. If you own the invoker, call setPipelineOptions on the argument provider before invoking @FinishBundle

Example fix

// before
customInvoker.invokeFinishBundle(provider); // provider has no options
// after
provider.setPipelineOptions(PipelineOptionsFactory.create());
customInvoker.invokeFinishBundle(provider);
Defensive patterns

Strategy: try-catch

Validate before calling

// Before invoking FinishBundle manually:
options = PipelineOptionsFactory.create();
provider.setPipelineOptions(options);

Try / catch

try {
  invoker.invokeFinishBundle(provider);
} catch (IllegalStateException e) {
  if (e.getMessage().equals("PipelineOptions not set")) {
    provider.setPipelineOptions(PipelineOptionsFactory.create());
    invoker.invokeFinishBundle(provider);
  } else throw e;
}

Prevention

When it happens

Trigger: A @FinishBundle method (or code it calls) calls c.pipelineOptions() while the wrapper's pipelineOptions field was never populated — typically invoking the DoFn manually without a runner or without invoking setup with options.

Common situations: Unit tests that call finishBundle contexts directly; custom invokers that forget setPipelineOptions; runner integrations not passing options.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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