apache/beam · error · IllegalStateException

fn.getIncompatibleGlobalWindowErrorMessage()

Error message

fn.getIncompatibleGlobalWindowErrorMessage()

What it means

Combine.globally/related transforms insert a default value for empty PCollections only if the output's windowing is compatible with GlobalWindows; otherwise the default's meaning is undefined and an IllegalStateException with the fn's incompatible-global-window message is thrown.

Solutions

  1. Call .withoutDefaults() so no default is inserted for empty windowed inputs
  2. Use .withHotKeyFanout-safe alternatives or re-window to GlobalWindows before combining if a global default is truly needed
  3. Provide an explicit default via .withDefault... style APIs where available

Example fix

// before
pc.apply(Combine.globally(myFn)) // windowed input
// after
pc.apply(Combine.globally(myFn).withoutDefaults())
Defensive patterns

Strategy: validation

Validate before calling

boolean safeForDefault = pc.getWindowingStrategy().getWindowFn().isCompatible(new GlobalWindows());
if (!safeForDefault) needWithoutDefaults = true;

Try / catch

try {
  return pc.apply(Combine.globally(fn));
} catch (IllegalStateException e) {
  if (e.getMessage() != null && e.getMessage().contains("window")) {
    return pc.apply(Combine.globally(fn).withoutDefaults());
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling Combine.globally(fn).withoutDefaults(false) (default insertion enabled) on a PCollection windowed with a non-global WindowFn (e.g. FixedWindows/SlidingWindows) — the fn must be windowing-safe to default.

Common situations: Combining a windowed stream without .withoutDefaults(); forgetting to add .withDefaultWorldWindowFn or trigger/windowing adjustments; a custom CombineFn whose getIncompatibleGlobalWindowErrorMessage names the incompatibility.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/Combine.java:1213

              .setCoder(KvCoder.of(VoidCoder.of(), input.getCoder()));

      Combine.PerKey<Void, InputT, OutputT> combine = Combine.fewKeys(fn, fnDisplayData);
      if (!sideInputs.isEmpty()) {
        combine = combine.withSideInputs(sideInputs);
      }

      PCollection<KV<Void, OutputT>> combined;
      if (fanout >= 2) {
        combined = withKeys.apply(combine.withHotKeyFanout(fanout));
      } else {
        combined = withKeys.apply(combine);
      }

      PCollection<OutputT> output = combined.apply(Values.create());

      if (insertDefault) {
        if (!output.getWindowingStrategy().getWindowFn().isCompatible(new GlobalWindows())) {
          throw new IllegalStateException(fn.getIncompatibleGlobalWindowErrorMessage());
        }
        return insertDefaultValueIfEmpty(output);
      } else {
        return output;
      }
    }

    @Override
    public void populateDisplayData(DisplayData.Builder builder) {
      super.populateDisplayData(builder);

      Combine.populateDisplayData(builder, fn, fnDisplayData);
      Combine.populateGlobalDisplayData(builder, fanout, insertDefault);
    }

    private PCollection<OutputT> insertDefaultValueIfEmpty(PCollection<OutputT> maybeEmpty) {
      final PCollectionView<Iterable<OutputT>> maybeEmptyView = maybeEmpty.apply(View.asIterable());

View on GitHub (pinned to 12126d8942)