{"record":{"id":"40ab86a6a72e30f7","repo":"apache/beam","slug":"datetime64-requires-a-joda-readableinstant-or-java-time","errorCode":null,"errorMessage":"DateTime64 requires a Joda ReadableInstant or java.time.Instant, got ","messagePattern":"DateTime64 requires a Joda ReadableInstant or java\\.time\\.Instant, got ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/clickhouse/src/main/java/org/apache/beam/sdk/io/clickhouse/ClickHouseWriter.java","lineNumber":101,"sourceCode":"   * 64-bit integer counting ticks of size 10<sup>-precision</sup> seconds since the Unix epoch.\n   *\n   * <p>Accepts either a Joda {@link ReadableInstant} (millisecond precision) or a {@link\n   * java.time.Instant} (nanosecond precision). Sub-tick fractions are truncated toward negative\n   * infinity, matching ClickHouse's own encoding for negative timestamps.\n   */\n  static long encodeDateTime64(Object value, int precision) {\n    long epochSecond;\n    int nanoOfSecond;\n    if (value instanceof java.time.Instant) {\n      java.time.Instant inst = (java.time.Instant) value;\n      epochSecond = inst.getEpochSecond();\n      nanoOfSecond = inst.getNano();\n    } else if (value instanceof ReadableInstant) {\n      long millis = ((ReadableInstant) value).getMillis();\n      epochSecond = Math.floorDiv(millis, 1000L);\n      nanoOfSecond = (int) Math.floorMod(millis, 1000L) * 1_000_000;\n    } else {\n      throw new IllegalArgumentException(\n          \"DateTime64 requires a Joda ReadableInstant or java.time.Instant, got \"\n              + (value == null ? \"null\" : value.getClass().getName()));\n    }\n    long subSecondTicks = nanoOfSecond / POW10[9 - precision];\n    return Math.addExact(Math.multiplyExact(epochSecond, POW10[precision]), subSecondTicks);\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  static void writeNullableValue(ClickHouseOutputStream stream, ColumnType columnType, Object value)\n      throws IOException {\n\n    if (value == null) {\n      BinaryStreamUtils.writeNull(stream);\n    } else {\n      BinaryStreamUtils.writeNonNull(stream);\n      writeValue(stream, columnType, value);\n    }\n  }","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/clickhouse/src/main/java/org/apache/beam/sdk/io/clickhouse/ClickHouseWriter.java#L83-L119","documentation":"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.","triggerScenarios":"Calling writeValue on a DateTime64 column with a String timestamp, epoch-millis Long, java.util.Date, or null instead of Instant/ReadableInstant.","commonSituations":"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.","solutions":["Convert to java.time.Instant before writing (Instant.parse(...), Instant.ofEpochMilli(millis), date.toInstant()).","Joda DateTime (ReadableInstant) values are also accepted directly.","Parse string timestamps with the correct DateTimeFormatter and zone upstream of the write.","Populate the Row field so nulls never reach the writer."],"exampleFix":"// before\nwriter.writeValue(\"2024-01-01 00:00:00\"); // String rejected\n// after\njava.time.Instant instant = java.time.Instant.parse(\"2024-01-01T00:00:00Z\");\nwriter.writeValue(instant);","handlingStrategy":"type-guard","validationCode":"import java.time.Instant;\nimport org.joda.time.ReadableInstant;\nboolean isDateTime64Compatible(Object v) {\n  return v instanceof Instant || v instanceof ReadableInstant;\n}","typeGuard":"java.time.Instant asInstant(Object v) {\n  if (v instanceof java.time.Instant) return (java.time.Instant) v;\n  if (v instanceof org.joda.time.ReadableInstant) return java.time.Instant.ofEpochMilli(((org.joda.time.ReadableInstant) v).getMillis());\n  if (v instanceof Long) return java.time.Instant.ofEpochMilli((Long) v);\n  if (v instanceof String) return java.time.Instant.parse((String) v);\n  throw new IllegalArgumentException(\"Not convertible to Instant: \" + v);\n}","tryCatchPattern":"try {\n  writer.encodeDateTime64(value, precision);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"DateTime64 requires\")) {\n    throw new SchemaMappingException(\"Row field must be Instant or ReadableInstant for DateTime64 column\");\n  }\n  throw e;\n}","preventionTips":["Define Beam Row schemas with Instant fields for DateTime64 columns.","Parse timestamp strings once at source ingestion, not at write time.","Convert java.util.Date via date.toInstant() and epoch millis via Instant.ofEpochMilli().","Handle nulls explicitly upstream so nulls never reach the writer."],"tags":["clickhouse","datetime","type-mismatch","beam"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}