apache/beam · error · CoderException

cannot encode a null Instant

Error message

cannot encode a null Instant

What it means

InstantCoder.encode() throws CoderException if the Instant value passed is null. Coder encodings in Beam are non-nullable by contract; the coder writes a fixed 8-byte lexicographically ordered millis value and cannot represent absence.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/coders/InstantCoder.java:47

 * A {@link Coder} for joda {@link Instant} that encodes it as a big endian {@link Long} shifted
 * such that lexicographic ordering of the bytes corresponds to chronological order.
 */
public class InstantCoder extends AtomicCoder<Instant> {
  public static InstantCoder of() {
    return INSTANCE;
  }

  /////////////////////////////////////////////////////////////////////////////

  private static final InstantCoder INSTANCE = new InstantCoder();
  private static final TypeDescriptor<Instant> TYPE_DESCRIPTOR = new TypeDescriptor<Instant>() {};

  private InstantCoder() {}

  @Override
  public void encode(Instant value, OutputStream outStream) throws CoderException, IOException {
    if (value == null) {
      throw new CoderException("cannot encode a null Instant");
    }

    // Converts {@link Instant} to a {@code long} representing its millis-since-epoch,
    // but shifted so that the byte representation of negative values are lexicographically
    // ordered before the byte representation of positive values.
    //
    // This deliberately utilizes the well-defined underflow for {@code long} values.
    // See http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2
    long shiftedMillis = value.getMillis() - Long.MIN_VALUE;
    BitConverters.writeBigEndianLong(shiftedMillis, outStream);
  }

  @Override
  public Instant decode(InputStream inStream) throws CoderException, IOException {
    long shiftedMillis;
    try {
      shiftedMillis = BitConverters.readBigEndianLong(inStream);
    } catch (EOFException | UTFDataFormatException exn) {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Wrap with NullableCoder.of(InstantCoder.of()) when nulls are legitimate.
  2. Filter or default null instants in the DoFn producing the elements.
  3. Parse timestamps defensively upstream, falling back to a defined default (e.g. Instant.EPOCH) rather than null.

Example fix

// before
Coder<Instant> c = InstantCoder.of(); // encode(null) throws
// after
Coder<Instant> c = NullableCoder.of(InstantCoder.of());
Defensive patterns

Strategy: validation

Validate before calling

if (instant != null) { coder.encode(instant, out); }

Prevention

When it happens

Trigger: Invoking InstantCoder.of().encode(null, outStream) directly, or the pipeline encoding a PCollection<Instant> element that is null (e.g. from a missing timestamp or unparseable input).

Common situations: Ingest pipelines where timestamp parsing failed and produced null; using InstantCoder inside structured coders for optional fields without NullableCoder.

Related errors


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