apache/beam · error · IllegalArgumentException

cannot encode a null tagged union

Error message

cannot encode a null tagged union

What it means

UnionCoder encodes a tagged union value by resolving which element coder to use via the union tag. This error is thrown when encode() is called with a null RawUnionValue, because there is no tag to dispatch on and no defined encoding for null.

Solutions

  1. Filter or map out null RawUnionValues before the coder is used (e.g. drop nulls in a preceding ParDo).
  2. Emit an empty/default union member instead of null, using a reserved union tag.
  3. If nulls must be representable, wrap the coder in NullableCoder.of(unionCoder).

Example fix

// before
unionCoder.encode(null, out);
// after
if (value != null) {
  unionCoder.encode(value, out);
} else {
  NullableCoder.of(unionCoder).encode(null, out);
}
Defensive patterns

Strategy: validation

Validate before calling

if (value == null) {
  throw new IllegalArgumentException("refusing to encode null union value");
}
unionCoder.encode(value, outStream);

Type guard

boolean isEncodable(RawUnionValue v) { return v != null && v.getUnionTag() >= 0; }

Prevention

When it happens

Trigger: Calling UnionCoder.encode (via getIndexForEncoding, invoked from index()) with a null RawUnionValue, e.g. encoding a null element inside a CoGroupByKey/TaggedKV stream.

Common situations: A PCollection feeding a CoGroupByKey contains null elements; user code emits null from a DoFn into a union-typed collection; a runner passes a null value during serialization.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/join/UnionCoder.java:48

/** A UnionCoder encodes RawUnionValues. */
@SuppressWarnings({
  "nullness" // TODO(https://github.com/apache/beam/issues/20497)
})
public class UnionCoder extends StructuredCoder<RawUnionValue> {
  // TODO: Think about how to integrate this with a schema object (i.e.
  // a tuple of tuple tags).
  /**
   * Builds a union coder with the given list of element coders. This list corresponds to a mapping
   * of union tag to Coder. Union tags start at 0.
   */
  public static UnionCoder of(List<Coder<?>> elementCoders) {
    return new UnionCoder(elementCoders);
  }

  private int getIndexForEncoding(RawUnionValue union) {
    if (union == null) {
      throw new IllegalArgumentException("cannot encode a null tagged union");
    }
    int index = union.getUnionTag();
    if (index < 0 || index >= elementCoders.size()) {
      throw new IllegalArgumentException(
          "union value index " + index + " not in range [0.." + (elementCoders.size() - 1) + "]");
    }
    return index;
  }

  @Override
  public void encode(RawUnionValue union, OutputStream outStream)
      throws IOException, CoderException {
    encode(union, outStream, Context.NESTED);
  }

  @SuppressWarnings("unchecked")
  @Override
  public void encode(RawUnionValue union, OutputStream outStream, Context context)

View on GitHub (pinned to 12126d8942)