apache/beam · error · CoderException

cannot encode a null ValueKind

Error message

cannot encode a null ValueKind

What it means

ValueKindCoder encodes a ValueKind as its protobuf enum number (a single byte) and rejects null with CoderException, since ValueKind has no null member. A null kind indicates an uninitialized field in the surrounding machinery rather than serializable data.

Solutions

  1. Initialize the ValueKind field before encoding (e.g. ValueKind.IMMUTABLE or the appropriate constant).
  2. Default null kinds to a valid sentinel enum constant at construction time.
  3. Verify ValueKindUtil.fromProto returns non-null for every enum number you emit.
  4. Inspect the stack trace to find which builder/constructor left the kind unset.

Example fix

// before
kindCoder.encode(kind, out); // kind may be null
// after
ValueKind safeKind = kind != null ? kind : ValueKind.IMMUTABLE;
kindCoder.encode(safeKind, out);
Defensive patterns

Strategy: validation

Validate before calling

if (kind == null) {
  throw new IllegalArgumentException("ValueKind must be set before encoding");
}

Type guard

static boolean encodable(ValueKind k) { return k != null; }

Try / catch

try {
  kindCoder.encode(kind, out);
} catch (CoderException e) {
  throw new SerializationException("Unset ValueKind", e);
}

Prevention

When it happens

Trigger: Calling ValueKindCoder.encode(null, out) directly; internal structures where a ValueKind field was never initialized; proto-to-ValueKind conversion code that left the field unset before encoding.

Common situations: Runner/harness integration code building element-kind metadata; proto conversions leaving optional ValueKind fields unset; custom pipeline fragment assembly skipping the kind field.

Related errors


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

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/coders/ValueKindCoder.java:50

 * Elements.ValueKind.Enum} number, so the wire format stays stable if the enum is reordered and
 * matches the portability representation.
 */
public class ValueKindCoder extends AtomicCoder<ValueKind> {

  public static ValueKindCoder of() {
    return INSTANCE;
  }

  private static final ValueKindCoder INSTANCE = new ValueKindCoder();
  private static final TypeDescriptor<ValueKind> TYPE_DESCRIPTOR =
      TypeDescriptor.of(ValueKind.class);

  private ValueKindCoder() {}

  @Override
  public void encode(ValueKind value, OutputStream outStream) throws IOException, CoderException {
    if (value == null) {
      throw new CoderException("cannot encode a null ValueKind");
    }
    outStream.write(ValueKindUtil.toProto(value).getNumber());
  }

  @Override
  public ValueKind decode(InputStream inStream) throws IOException, CoderException {
    int number = inStream.read();
    if (number == -1) {
      throw new CoderException(new EOFException("EOF encountered decoding a ValueKind"));
    }
    Elements.ValueKind.@Nullable Enum proto = Elements.ValueKind.Enum.forNumber(number);
    if (proto == null) {
      throw new CoderException("Unknown ValueKind number: " + number);
    }

    return ValueKindUtil.fromProto(proto);
  }

View on GitHub (pinned to 12126d8942)