{"record":{"id":"5188ebf7f683f92b","repo":"apache/beam","slug":"cannot-encode-a-null-instant","errorCode":null,"errorMessage":"cannot encode a null Instant","messagePattern":"cannot encode a null Instant","errorType":"exception","errorClass":"CoderException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/coders/InstantCoder.java","lineNumber":47,"sourceCode":" * A {@link Coder} for joda {@link Instant} that encodes it as a big endian {@link Long} shifted\n * such that lexicographic ordering of the bytes corresponds to chronological order.\n */\npublic class InstantCoder extends AtomicCoder<Instant> {\n  public static InstantCoder of() {\n    return INSTANCE;\n  }\n\n  /////////////////////////////////////////////////////////////////////////////\n\n  private static final InstantCoder INSTANCE = new InstantCoder();\n  private static final TypeDescriptor<Instant> TYPE_DESCRIPTOR = new TypeDescriptor<Instant>() {};\n\n  private InstantCoder() {}\n\n  @Override\n  public void encode(Instant value, OutputStream outStream) throws CoderException, IOException {\n    if (value == null) {\n      throw new CoderException(\"cannot encode a null Instant\");\n    }\n\n    // Converts {@link Instant} to a {@code long} representing its millis-since-epoch,\n    // but shifted so that the byte representation of negative values are lexicographically\n    // ordered before the byte representation of positive values.\n    //\n    // This deliberately utilizes the well-defined underflow for {@code long} values.\n    // See http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2\n    long shiftedMillis = value.getMillis() - Long.MIN_VALUE;\n    BitConverters.writeBigEndianLong(shiftedMillis, outStream);\n  }\n\n  @Override\n  public Instant decode(InputStream inStream) throws CoderException, IOException {\n    long shiftedMillis;\n    try {\n      shiftedMillis = BitConverters.readBigEndianLong(inStream);\n    } catch (EOFException | UTFDataFormatException exn) {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/InstantCoder.java#L29-L65","documentation":"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.","triggerScenarios":"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).","commonSituations":"Ingest pipelines where timestamp parsing failed and produced null; using InstantCoder inside structured coders for optional fields without NullableCoder.","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."],"exampleFix":"// before\nCoder<Instant> c = InstantCoder.of(); // encode(null) throws\n// after\nCoder<Instant> c = NullableCoder.of(InstantCoder.of());","handlingStrategy":"validation","validationCode":"if (instant != null) { coder.encode(instant, out); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["java","apache-beam","coders","null","instant"],"backgroundTag":"null-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}