{"record":{"id":"cdf2e4f25a3ed9a4","repo":"apache/beam","slug":"the-groupbykey-requires-its-output-coder-to-be-s-but-found-s","errorCode":null,"errorMessage":"the GroupByKey requires its output coder to be %s but found %s.","messagePattern":"the GroupByKey requires its output coder to be (.+?) but found (.+?)\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/GroupByKey.java","lineNumber":209,"sourceCode":"                  + \"https://s.apache.org/finishing-triggers-drop-data \"\n                  + \"for details.\",\n              windowingStrategy.getTrigger()));\n    }\n  }\n\n  @Override\n  public void validate(\n      @Nullable PipelineOptions options,\n      Map<TupleTag<?>, PCollection<?>> inputs,\n      Map<TupleTag<?>, PCollection<?>> outputs) {\n    PCollection<?> input = Iterables.getOnlyElement(inputs.values());\n    KvCoder<K, V> inputCoder = getInputKvCoder(input.getCoder());\n\n    // Ensure that the output coder key and value types aren't different.\n    Coder<?> outputCoder = Iterables.getOnlyElement(outputs.values()).getCoder();\n    KvCoder<?, ?> expectedOutputCoder = getOutputKvCoder(inputCoder);\n    if (!expectedOutputCoder.equals(outputCoder)) {\n      throw new IllegalStateException(\n          String.format(\n              \"the GroupByKey requires its output coder to be %s but found %s.\",\n              expectedOutputCoder, outputCoder));\n    }\n  }\n\n  // Note that Never trigger finishes *at* GC time so it is OK, and\n  // AfterWatermark.fromEndOfWindow() finishes at end-of-window time so it is\n  // OK if there is no allowed lateness.\n  private static boolean triggerIsSafe(WindowingStrategy<?, ?> windowingStrategy) {\n    if (!windowingStrategy.getTrigger().mayFinish()) {\n      return true;\n    }\n\n    if (windowingStrategy.getTrigger() instanceof NeverTrigger) {\n      return true;\n    }\n","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/GroupByKey.java#L191-L227","documentation":"During validate(), GroupByKey recomputes the KvCoder it expects its output PCollection to carry (KvCoder<K, Iterable<V>> derived from the input coder) and compares it with the coder actually set on the output. A mismatch means something changed the output coder incorrectly, which would break downstream coders/serialization, so Beam throws IllegalStateException.","triggerScenarios":"A user or intermediate transform calls output.setCoder(...) on GroupByKey's output with a coder different from getOutputKvCoder(inputCoder) — e.g. set a KvCoder with a different value coder after applying GroupByKey, or an output-coder-override registry supplies the wrong coder.","commonSituations":"Manually overriding output coders to 'optimize' serialization; wrapping GroupByKey in a composite that resets coders; custom pipeline-level coder registration that substitutes a coder for KV<K, Iterable<V>>.","solutions":["Remove any explicit setCoder() on GroupByKey's output and let Beam infer KvCoder<K, Iterable<V>>","If a custom coder is needed, change the input coder so getOutputKvCoder derives the desired output coder","Ensure any coder overrides registered pipeline-wide match exactly KvCoder.of(inputKeyCoder, IterableCoder.of(inputValueCoder))","Compare the two coders in the message: align the found coder's structural types (key coder, iterable value coder) with the expected one"],"exampleFix":"// before\nPCollection<KV<K, Iterable<V>>> grouped = input.apply(GroupByKey.create());\ngrouped.setCoder(KvCoder.of(keyCoder, ListCoder.of(valueCoder))); // wrong shape\n// after\nPCollection<KV<K, Iterable<V>>> grouped = input.apply(GroupByKey.create());\n// no explicit setCoder; Beam derives KvCoder<K, IterableCoder<V>> from the input coder","handlingStrategy":"type-guard","validationCode":"KvCoder<?, ?> expected = KvCoder.of(\n    ((KvCoder<?, ?>) input.getCoder()).getKeyCoder(),\n    IterableCoder.of(((KvCoder<?, ?>) input.getCoder()).getValueCoder()));\nif (!expected.equals(grouped.getCoder())) { /* remove or fix setCoder */ }","typeGuard":"static <K,V> boolean outputCoderIsValid(PCollection<KV<K, Iterable<V>>> out) {\n  return out.getCoder() instanceof KvCoder<?, ?>\n      && ((KvCoder<?, ?>) out.getCoder()).getValueCoder() instanceof IterableCoder<?>;\n}","tryCatchPattern":"try {\n  pipeline.run();\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"requires its output coder\")) { /* drop the manual setCoder */ }\n  else throw e;\n}","preventionTips":["Don't call setCoder() on GroupByKey output","Let Beam infer coders from transform types","Audit pipeline-wide coder registries for KV<K, Iterable<V>> overrides"],"tags":["apache-beam","java","coder","groupbykey","validation"],"backgroundTag":"type-mismatch","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"}