apache/beam · error · IllegalStateException

Continuation of a OnceTrigger must be a OnceTrigger

Error message

Continuation of a OnceTrigger must be a OnceTrigger

What it means

OnceTrigger subclasses (AfterCount, AfterFirst, etc.) must maintain the invariant that their continuation — the trigger used after they fire — is itself a OnceTrigger, otherwise firing guarantees break. The OnceTrigger.getContinuationTrigger override checks the super-produced continuation and throws IllegalStateException if a subclass returned a non-OnceTrigger continuation.

Solutions

  1. Make the custom trigger's continuation a OnceTrigger subclass, e.g. AfterWatermark.pastEndOfWindow() or never()
  2. Wrap continuation logic in a custom OnceTrigger subclass rather than AfterAll/Repeatedly
  3. If the trigger genuinely can fire multiple times, extend Trigger directly instead of OnceTrigger

Example fix

// before
@Override protected Trigger getContinuationTrigger(List<Trigger> conts) {
  return AfterAll.of(conts); // not a OnceTrigger -> IllegalStateException
}
// after
@Override protected Trigger getContinuationTrigger(List<Trigger> conts) {
  return AfterWatermark.pastEndOfWindow();
}
Defensive patterns

Strategy: validation

Validate before calling

Trigger cont = myOnceTrigger.getContinuationTrigger(); if (!(cont instanceof OnceTrigger)) throw new IllegalStateException("Custom OnceTrigger continuation must be a OnceTrigger");

Type guard

boolean validOnceTrigger(Trigger t) { return t instanceof OnceTrigger && t.getContinuationTrigger() instanceof OnceTrigger; }

Try / catch

try { Trigger c = trigger.getContinuationTrigger(); } catch (IllegalStateException e) { LOG.error("Fix custom OnceTrigger continuation", e); }

Prevention

When it happens

Trigger: Defining a custom OnceTrigger whose getContinuationTrigger(List) returns a plain Trigger (e.g. AfterAll or Repeatedly.forever) instead of a OnceTrigger subclass, then calling getContinuationTrigger().

Common situations: Custom trigger development in Beam pipelines; upgrading Beam where trigger semantics tightened; test code (testContinuation) exercising continuation triggers of custom triggers.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/windowing/Trigger.java:253

   * <p>Triggers that are guaranteed to fire at most once should extend {@link OnceTrigger} rather
   * than the general {@link Trigger} class to indicate that behavior.
   */
  @Internal
  public abstract static class OnceTrigger extends Trigger {
    protected OnceTrigger(List<Trigger> subTriggers) {
      super(subTriggers);
    }

    @Override
    public final boolean mayFinish() {
      return true;
    }

    @Override
    public final OnceTrigger getContinuationTrigger() {
      Trigger continuation = super.getContinuationTrigger();
      if (!(continuation instanceof OnceTrigger)) {
        throw new IllegalStateException("Continuation of a OnceTrigger must be a OnceTrigger");
      }
      return (OnceTrigger) continuation;
    }
  }
}

View on GitHub (pinned to 12126d8942)