{"record":{"id":"30b2c8f2fe911af9","repo":"apache/beam","slug":"continuation-of-a-oncetrigger-must-be-a-oncetrigger","errorCode":null,"errorMessage":"Continuation of a OnceTrigger must be a OnceTrigger","messagePattern":"Continuation of a OnceTrigger must be a OnceTrigger","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/windowing/Trigger.java","lineNumber":253,"sourceCode":"   * <p>Triggers that are guaranteed to fire at most once should extend {@link OnceTrigger} rather\n   * than the general {@link Trigger} class to indicate that behavior.\n   */\n  @Internal\n  public abstract static class OnceTrigger extends Trigger {\n    protected OnceTrigger(List<Trigger> subTriggers) {\n      super(subTriggers);\n    }\n\n    @Override\n    public final boolean mayFinish() {\n      return true;\n    }\n\n    @Override\n    public final OnceTrigger getContinuationTrigger() {\n      Trigger continuation = super.getContinuationTrigger();\n      if (!(continuation instanceof OnceTrigger)) {\n        throw new IllegalStateException(\"Continuation of a OnceTrigger must be a OnceTrigger\");\n      }\n      return (OnceTrigger) continuation;\n    }\n  }\n}\n","sourceCodeStart":235,"sourceCodeEnd":259,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/windowing/Trigger.java#L235-L259","documentation":"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.","triggerScenarios":"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().","commonSituations":"Custom trigger development in Beam pipelines; upgrading Beam where trigger semantics tightened; test code (testContinuation) exercising continuation triggers of custom triggers.","solutions":["Make the custom trigger's continuation a OnceTrigger subclass, e.g. AfterWatermark.pastEndOfWindow() or never()","Wrap continuation logic in a custom OnceTrigger subclass rather than AfterAll/Repeatedly","If the trigger genuinely can fire multiple times, extend Trigger directly instead of OnceTrigger"],"exampleFix":"// before\n@Override protected Trigger getContinuationTrigger(List<Trigger> conts) {\n  return AfterAll.of(conts); // not a OnceTrigger -> IllegalStateException\n}\n// after\n@Override protected Trigger getContinuationTrigger(List<Trigger> conts) {\n  return AfterWatermark.pastEndOfWindow();\n}","handlingStrategy":"validation","validationCode":"Trigger cont = myOnceTrigger.getContinuationTrigger(); if (!(cont instanceof OnceTrigger)) throw new IllegalStateException(\"Custom OnceTrigger continuation must be a OnceTrigger\");","typeGuard":"boolean validOnceTrigger(Trigger t) { return t instanceof OnceTrigger && t.getContinuationTrigger() instanceof OnceTrigger; }","tryCatchPattern":"try { Trigger c = trigger.getContinuationTrigger(); } catch (IllegalStateException e) { LOG.error(\"Fix custom OnceTrigger continuation\", e); }","preventionTips":["When extending OnceTrigger, return only OnceTrigger subclasses (never(), AfterWatermark.pastEndOfWindow(), AfterCount...)","Run Beam's trigger continuation unit tests (testContinuation pattern) for custom triggers","Extend plain Trigger if the trigger can fire more than once"],"tags":["java","apache-beam","trigger","invariant-violation"],"backgroundTag":"internal-invariant-violation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}