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
- Wrap with NullableCoder.of(InstantCoder.of()) when nulls are legitimate.
- Filter or default null instants in the DoFn producing the elements.
- 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
- Default unparseable timestamps to Instant.EPOCH or a sentinel instead of null.
- Wrap optional instants with NullableCoder.of(InstantCoder.of()).
- Validate timestamp parsing in ingestion transforms.
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
- cannot encode a null {iterableName}
- cannot encode a null Iterable
- cannot encode a null KV
- cannot encode a null Integer
- cannot encode a null Long
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/5188ebf7f683f92b.
Report an issue: GitHub.