apache/beam · error · IllegalArgumentException

DateTime64 requires a Joda ReadableInstant or…

Error message

DateTime64 requires a Joda ReadableInstant or java.time.Instant, got 

What it means

Thrown by ClickHouseWriter.encodeDateTime64 when the value for a DateTime64 column is neither a java.time.Instant nor a Joda ReadableInstant. DateTime64 encoding needs an instant-like type to compute epoch seconds and sub-second nanos; other types (String, Long, java.util.Date, null) are rejected explicitly, with 'null' reported by name.

Solutions

  1. Convert to java.time.Instant before writing (Instant.parse(...), Instant.ofEpochMilli(millis), date.toInstant()).
  2. Joda DateTime (ReadableInstant) values are also accepted directly.
  3. Parse string timestamps with the correct DateTimeFormatter and zone upstream of the write.
  4. Populate the Row field so nulls never reach the writer.

Example fix

// before
writer.writeValue("2024-01-01 00:00:00"); // String rejected
// after
java.time.Instant instant = java.time.Instant.parse("2024-01-01T00:00:00Z");
writer.writeValue(instant);
Defensive patterns

Strategy: type-guard

Validate before calling

import java.time.Instant;
import org.joda.time.ReadableInstant;
boolean isDateTime64Compatible(Object v) {
  return v instanceof Instant || v instanceof ReadableInstant;
}

Type guard

java.time.Instant asInstant(Object v) {
  if (v instanceof java.time.Instant) return (java.time.Instant) v;
  if (v instanceof org.joda.time.ReadableInstant) return java.time.Instant.ofEpochMilli(((org.joda.time.ReadableInstant) v).getMillis());
  if (v instanceof Long) return java.time.Instant.ofEpochMilli((Long) v);
  if (v instanceof String) return java.time.Instant.parse((String) v);
  throw new IllegalArgumentException("Not convertible to Instant: " + v);
}

Try / catch

try {
  writer.encodeDateTime64(value, precision);
} catch (IllegalArgumentException e) {
  if (e.getMessage() != null && e.getMessage().contains("DateTime64 requires")) {
    throw new SchemaMappingException("Row field must be Instant or ReadableInstant for DateTime64 column");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling writeValue on a DateTime64 column with a String timestamp, epoch-millis Long, java.util.Date, or null instead of Instant/ReadableInstant.

Common situations: Rows built from JSON/CSV sources where timestamps remain strings; passing System.currentTimeMillis() directly; legacy code carrying java.util.Date; missing fields leaving nulls in the Row.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/io/clickhouse/src/main/java/org/apache/beam/sdk/io/clickhouse/ClickHouseWriter.java:101

   * 64-bit integer counting ticks of size 10<sup>-precision</sup> seconds since the Unix epoch.
   *
   * <p>Accepts either a Joda {@link ReadableInstant} (millisecond precision) or a {@link
   * java.time.Instant} (nanosecond precision). Sub-tick fractions are truncated toward negative
   * infinity, matching ClickHouse's own encoding for negative timestamps.
   */
  static long encodeDateTime64(Object value, int precision) {
    long epochSecond;
    int nanoOfSecond;
    if (value instanceof java.time.Instant) {
      java.time.Instant inst = (java.time.Instant) value;
      epochSecond = inst.getEpochSecond();
      nanoOfSecond = inst.getNano();
    } else if (value instanceof ReadableInstant) {
      long millis = ((ReadableInstant) value).getMillis();
      epochSecond = Math.floorDiv(millis, 1000L);
      nanoOfSecond = (int) Math.floorMod(millis, 1000L) * 1_000_000;
    } else {
      throw new IllegalArgumentException(
          "DateTime64 requires a Joda ReadableInstant or java.time.Instant, got "
              + (value == null ? "null" : value.getClass().getName()));
    }
    long subSecondTicks = nanoOfSecond / POW10[9 - precision];
    return Math.addExact(Math.multiplyExact(epochSecond, POW10[precision]), subSecondTicks);
  }

  @SuppressWarnings("unchecked")
  static void writeNullableValue(ClickHouseOutputStream stream, ColumnType columnType, Object value)
      throws IOException {

    if (value == null) {
      BinaryStreamUtils.writeNull(stream);
    } else {
      BinaryStreamUtils.writeNonNull(stream);
      writeValue(stream, columnType, value);
    }
  }

View on GitHub (pinned to 12126d8942)