apache/iceberg · error · IllegalArgumentException

Cannot convert java.util.Date to variant without a…

Error message

Cannot convert java.util.Date to variant without a recognized logical type schema (expected Timestamp, Time, or Date but got: ${logicalName})

What it means

temporalObjectToVariantValue throws this IllegalArgumentException when a java.util.Date is converted to a Variant but the Connect schema lacks a recognized logical type. Date is ambiguous without logical type info (Timestamp, Time, or Date); otherwise the converter cannot know whether to emit a variant timestamp, time, or date value.

Solutions

  1. Attach Timestamp/Time/Date logical types via Timestamp.builder()/Time.builder()/Date.builder() when building the Connect schema
  2. Convert java.util.Date to java.time types (Instant, LocalTime, LocalDate) before the sink so no logical schema is needed
  3. Use TimestampConverter SMT to add the proper logical type
  4. Avoid schemaless records for variant fields containing temporal values

Example fix

// before
Schema schema = SchemaBuilder.int64().build(); // no logical type
// after
Schema schema = Timestamp.builder().schema(SchemaBuilder.int64().build()).build();
Defensive patterns

Strategy: validation

Validate before calling

if (value instanceof java.util.Date) {
  String logical = schema != null && schema.name() != null ? schema.name() : null;
  boolean ok = org.apache.kafka.connect.data.Timestamp.LOGICAL_NAME.equals(logical)
      || org.apache.kafka.connect.data.Time.LOGICAL_NAME.equals(logical)
      || org.apache.kafka.connect.data.Date.LOGICAL_NAME.equals(logical);
  if (!ok) throw new IllegalStateException("java.util.Date needs Timestamp/Time/Date logical schema, got: " + logical);
}

Type guard

static boolean dateHasLogicalSchema(org.apache.kafka.connect.data.Schema s) {
  if (s == null || s.name() == null) return false;
  return Timestamp.LOGICAL_NAME.equals(s.name())
      || Time.LOGICAL_NAME.equals(s.name())
      || Date.LOGICAL_NAME.equals(s.name());
}

Try / catch

try {
  converter.convertValue(dateValue, variantType);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("recognized logical type schema")) {
    log.error("Attach Timestamp/Time/Date logical schema or convert to java.time first", e);
    // fallback: convert to Instant before sinking
  }
}

Prevention

When it happens

Trigger: A java.util.Date value reaches variant conversion with schema null, a plain (non-logical) schema, or a logical type other than org.apache.kafka.connect.data.{Timestamp,Time,Date}.

Common situations: Schemaless mode (no schema attached to the record) delivering java.util.Date values; a custom logical type name from another converter; schema stripped by an SMT before the sink.

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/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/85a76a538e9fbb71. Report an issue: GitHub.

Appendix: source

Thrown at kafka-connect/kafka-connect/src/main/java/org/apache/iceberg/connect/data/RecordConverter.java:764

    if (value instanceof LocalTime localTime) {
      return Variants.ofTime(DateTimeUtil.microsFromTime(localTime));
    }
    if (value instanceof Date date) {
      String logicalName = schema != null ? schema.name() : null;
      // Connect represents Timestamp, Time, and Date logical types as java.util.Date at runtime;
      // normalize to Instant once, then interpret using the schema logical type name.
      Instant connectInstant = date.toInstant();
      if (org.apache.kafka.connect.data.Timestamp.LOGICAL_NAME.equals(logicalName)) {
        return Variants.ofTimestamptz(DateTimeUtil.microsFromInstant(connectInstant));
      }
      if (org.apache.kafka.connect.data.Time.LOGICAL_NAME.equals(logicalName)) {
        LocalTime utcTime = connectInstant.atZone(ZoneOffset.UTC).toLocalTime();
        return Variants.ofTime(DateTimeUtil.microsFromTime(utcTime));
      }
      if (org.apache.kafka.connect.data.Date.LOGICAL_NAME.equals(logicalName)) {
        return Variants.ofDate(DateTimeUtil.daysFromInstant(connectInstant));
      }
      throw new IllegalArgumentException(
          "Cannot convert java.util.Date to variant without a recognized logical type schema"
              + " (expected Timestamp, Time, or Date but got: "
              + logicalName
              + ")");
    }
    return null;
  }

  /**
   * Converts a Number to VariantValue; throw IllegalArgumentException if the value is not a
   * supported number representation.
   */
  private static VariantValue numberToVariantValue(Number number) {
    if (number instanceof BigDecimal bigDecimal) {
      return Variants.of(bigDecimal);
    }
    if (number instanceof BigInteger bigInteger) {
      return Variants.of(new BigDecimal(bigInteger));

View on GitHub (pinned to 86d9c8fc54)