apache/beam · error · IllegalStateException

Combine.GroupedValues requires its input values to use…

Error message

Combine.GroupedValues requires its input values to use IterableCoder

What it means

Combine.GroupedValues requires the value side of the input KvCoder to be an IterableCoder, since its input is KV<K, Iterable<V>> after grouping. When the value coder is any other coder (e.g. a ListCoder, or a raw element coder), Beam throws IllegalStateException because it cannot extract the element coder needed to build the output coder.

Solutions

  1. Produce the input with GroupByKey so the value coder is IterableCoder<V>.
  2. If setting coders manually, use IterableCoder.of(elemCoder) for the value side, not ListCoder.
  3. Reorder: apply GroupedValues only to the output of GroupByKey (or GroupByKey-derived transforms like Combine.perKey).
  4. For list-valued inputs, switch the value coder to IterableCoder.of(...), which GroupedValues recognizes.

Example fix

// before
kvInput.setCoder(KvCoder.of(StringUtf8Coder.of(), ListCoder.of(VarIntCoder.of())));
kvInput.apply(Combine.groupedValues(sumFn));
// after
kvInput.setCoder(KvCoder.of(StringUtf8Coder.of(), IterableCoder.of(VarIntCoder.of())));
kvInput.apply(Combine.groupedValues(sumFn));
Defensive patterns

Strategy: type-guard

Validate before calling

Coder<?> valCoder = ((KvCoder<?,?>) grouped.getCoder()).getValueCoder(); if (!(valCoder instanceof IterableCoder)) { throw new IllegalStateException("value coder must be IterableCoder, got " + valCoder); }

Type guard

boolean hasIterableValueCoder(PCollection<?> pc) { return pc.getCoder() instanceof KvCoder && ((KvCoder<?,?>) pc.getCoder()).getValueCoder() instanceof IterableCoder; }

Try / catch

try { grouped.apply(Combine.groupedValues(fn)); } catch (IllegalStateException e) { if (e.getMessage().contains("IterableCoder")) { /* switch value coder to IterableCoder.of(elemCoder) */ } throw e; }

Prevention

When it happens

Trigger: Applying Combine.GroupedValues to a KV collection whose value coder is not IterableCoder — e.g. manually setting the coder to ListCoder, or applying GroupedValues directly to KV<K, List<V>> built by a custom transform that coded values as a list rather than an Iterable.

Common situations: Custom transforms producing grouped values with List/Collection coders instead of IterableCoder; replacing the inferred coder after GroupByKey; misuse of GroupedValues on non-grouped data.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

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

    public AppliedCombineFn<? super K, ? super InputT, ?, OutputT> getAppliedFn(
        CoderRegistry registry,
        Coder<? extends KV<K, ? extends Iterable<InputT>>> inputCoder,
        WindowingStrategy<?, ?> windowingStrategy) {
      KvCoder<K, InputT> kvCoder = getKvCoder(inputCoder);
      return AppliedCombineFn.withInputCoder(fn, registry, kvCoder, sideInputs, windowingStrategy);
    }

    private KvCoder<K, InputT> getKvCoder(
        Coder<? extends KV<K, ? extends Iterable<InputT>>> inputCoder) {
      if (!(inputCoder instanceof KvCoder)) {
        throw new IllegalStateException("Combine.GroupedValues requires its input to use KvCoder");
      }
      @SuppressWarnings({"unchecked", "rawtypes"})
      KvCoder<K, ? extends Iterable<InputT>> kvCoder = (KvCoder) inputCoder;
      Coder<K> keyCoder = kvCoder.getKeyCoder();
      Coder<? extends Iterable<InputT>> kvValueCoder = kvCoder.getValueCoder();
      if (!(kvValueCoder instanceof IterableCoder)) {
        throw new IllegalStateException(
            "Combine.GroupedValues requires its input values to use " + "IterableCoder");
      }
      @SuppressWarnings("unchecked")
      IterableCoder<InputT> inputValuesCoder = (IterableCoder<InputT>) kvValueCoder;
      Coder<InputT> inputValueCoder = inputValuesCoder.getElemCoder();
      return KvCoder.of(keyCoder, inputValueCoder);
    }

    @Override
    public void populateDisplayData(DisplayData.Builder builder) {
      super.populateDisplayData(builder);
      Combine.populateDisplayData(builder, fn, fnDisplayData);
    }
  }
}

View on GitHub (pinned to 12126d8942)