{"record":{"id":"33e3730f293d0bf6","repo":"apache/beam","slug":"groupbykey-cannot-be-applied-to-non-bounded-pcollection-in","errorCode":null,"errorMessage":"GroupByKey cannot be applied to non-bounded PCollection in the GlobalWindow without a trigger. Use a Window.into or Window.triggering transform prior to GroupByKey.","messagePattern":"GroupByKey cannot be applied to non-bounded PCollection in the GlobalWindow without a trigger\\. Use a Window\\.into or Window\\.triggering transform prior to GroupByKey\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/GroupByKey.java","lineNumber":180,"sourceCode":"\n  /**\n   * For Beam internal use only. Tells runner that this is a GBK wrapped around of a\n   * GroupByEncryptedKey\n   */\n  public boolean surroundsGBEK() {\n    return this.surroundsGBEK;\n  }\n\n  /////////////////////////////////////////////////////////////////////////////\n\n  public static void applicableTo(PCollection<?> input) {\n    WindowingStrategy<?, ?> windowingStrategy = input.getWindowingStrategy();\n    // Verify that the input PCollection is bounded, or that there is windowing/triggering being\n    // used. Without this, the watermark (at end of global window) will never be reached.\n    if (windowingStrategy.getWindowFn() instanceof GlobalWindows\n        && windowingStrategy.getTrigger() instanceof DefaultTrigger\n        && input.isBounded() != IsBounded.BOUNDED) {\n      throw new IllegalStateException(\n          \"GroupByKey cannot be applied to non-bounded PCollection in the GlobalWindow without a\"\n              + \" trigger. Use a Window.into or Window.triggering transform prior to GroupByKey.\");\n    }\n\n    // Validate that the trigger does not finish before garbage collection time\n    if (!triggerIsSafe(windowingStrategy)) {\n      throw new IllegalArgumentException(\n          String.format(\n              \"Unsafe trigger '%s' may lose data, did you mean to wrap it in\"\n                  + \"`Repeatedly.forever(...)`?%nSee \"\n                  + \"https://s.apache.org/finishing-triggers-drop-data \"\n                  + \"for details.\",\n              windowingStrategy.getTrigger()));\n    }\n  }\n\n  @Override\n  public void validate(","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/GroupByKey.java#L162-L198","documentation":"GroupByKey in the GlobalWindow with the DefaultTrigger never fires on an unbounded stream because the end-of-global-window watermark is never reached, so results would never be emitted. Beam rejects this configuration up front in applicableTo() with an IllegalStateException.","triggerScenarios":"Applying GroupByKey (directly, not inside GBK-into-Batches or with windowing) to an unbounded PCollection (streaming source such as Pub/Sub, Kafka, or an unbounded PTransform input) whose windowing strategy is GlobalWindows with the DefaultTrigger.","commonSituations":"Streaming pipelines that read from an unbounded source and apply GroupByKey without first calling Window.into(...); prototypes written batch-first and later repointed at a streaming source; forgetting fixed/sliding/session windows in a streaming job.","solutions":["Add a windowing transform before GroupByKey, e.g. input.apply(Window.into(FixedWindows.of(Duration.standardMinutes(1))))","Add a non-default triggering strategy, e.g. Window.triggering(Repeatedly.forever(AfterProcessingTime.pastFirstElementInPane().plusDelayOf(Duration.standardSeconds(30))))","Ensure the source PCollection is truly bounded if you intended a batch pipeline (check the connector's isBounded)","For streaming aggregation, consider GroupIntoBatches or Beam's streaming SQL/MBR alternatives that handle unbounded grouping"],"exampleFix":"// before\nunboundedPCollection.apply(GroupByKey.create());\n// after\nunboundedPCollection\n    .apply(Window.<KV<K,V>>into(FixedWindows.of(Duration.standardMinutes(1))))\n    .apply(GroupByKey.create());","handlingStrategy":"validation","validationCode":"if (input.isBounded() != IsBounded.BOUNDED\n    && input.getWindowingStrategy().getWindowFn() instanceof GlobalWindows\n    && input.getWindowingStrategy().getTrigger() instanceof DefaultTrigger) {\n  throw new IllegalArgumentException(\"Apply Window.into/triggering before GroupByKey\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  grouped = unbounded.apply(GroupByKey.create());\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"non-bounded PCollection in the GlobalWindow\")) { /* add windowing */ }\n  else throw e;\n}","preventionTips":["Never apply raw GroupByKey directly on streaming sources","Add Window.into(...) as the first step after any unbounded Read","Document windowing requirements in pipeline composition utilities"],"tags":["apache-beam","java","streaming","windowing","groupbykey"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}