apache/iceberg · error · ConnectException

Cannot convert date

Error message

Cannot convert date: ${value}

What it means

RecordConverter.convertDateValue throws this ConnectException when a value mapped to an Iceberg Date column is not a Number (days since epoch), LocalDate, java.util.Date, or a parseable date string. The sink cannot interpret the value as a calendar date.

Solutions

  1. Ensure the Connect schema declares the field as int32 with the Date logical type (or int32 days / string date)
  2. Use TimestampConverter SMT to normalize the value to Date/unix time before the sink
  3. Fix the source record so the date is an ISO-8601 string or epoch-days number
  4. Verify the field mapping in the connector config hasn't shifted to a different field

Example fix

// before
SchemaBuilder.string().build(); // "not-a-date" reaches convertDateValue
// after
Date.Builder logical = Date.builder().schema(SchemaBuilder.int32().build()); // epoch days
Defensive patterns

Strategy: validation

Validate before calling

// check before sink
Object v = record.value().get("dateField");
if (!(v instanceof Number || v instanceof LocalDate || v instanceof java.util.Date || v instanceof String)) {
  throw new IllegalStateException("Date field bad type: " + (v == null ? "null" : v.getClass()));
}

Type guard

static boolean isDateCompatible(Object v) {
  return v == null || v instanceof Number || v instanceof LocalDate
      || v instanceof java.util.Date || v instanceof String;
}

Try / catch

try {
  converter.convertValue(value, Types.DateType.get());
} catch (ConnectException e) {
  log.error("Date conversion failed: " + e.getMessage(), e);
  // send to dead-letter queue instead of failing the task
}

Prevention

When it happens

Trigger: A Date field receives a nested struct, map, boolean, or arbitrary object; or a String that fails date parsing reaches convertDateValue via convertValue or ts (timestamp-to-date coercion).

Common situations: Producer schema changed a date field to a complex type; Connect's JSON converter delivered an unparsed string or object; an SMT cast a timestamp into the wrong field that the sink maps to Date.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/c3a25b330b41269e. Report an issue: GitHub.

Appendix: source

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

      return (ByteBuffer) value;
    }
    throw new IllegalArgumentException("Cannot convert to binary: " + value.getClass().getName());
  }

  @SuppressWarnings("JavaUtilDate")
  protected LocalDate convertDateValue(Object value) {
    if (value instanceof Number) {
      int days = ((Number) value).intValue();
      return DateTimeUtil.dateFromDays(days);
    } else if (value instanceof String) {
      return LocalDate.parse((String) value);
    } else if (value instanceof LocalDate) {
      return (LocalDate) value;
    } else if (value instanceof Date) {
      int days = (int) (((Date) value).getTime() / 1000 / 60 / 60 / 24);
      return DateTimeUtil.dateFromDays(days);
    }
    throw new ConnectException("Cannot convert date: " + value);
  }

  @SuppressWarnings("JavaUtilDate")
  protected LocalTime convertTimeValue(Object value) {
    if (value instanceof Number) {
      long millis = ((Number) value).longValue();
      return DateTimeUtil.timeFromMicros(millis * 1000);
    } else if (value instanceof String) {
      return LocalTime.parse((String) value);
    } else if (value instanceof LocalTime) {
      return (LocalTime) value;
    } else if (value instanceof Date) {
      long millis = ((Date) value).getTime();
      return DateTimeUtil.timeFromMicros(millis * 1000);
    }
    throw new ConnectException("Cannot convert time: " + value);
  }

View on GitHub (pinned to 86d9c8fc54)