apache/iceberg · error · java.lang.IllegalArgumentException

Unexpected object type for DATE logical type. Received: ${ob

Error message

Unexpected object type for DATE logical type. Received: ${object}

What it means

Thrown by AvroToRowDataConverters.convertToDate when an Avro 'date' logical type field produces an object that is neither java.time.LocalDate nor a Joda-convertible type. It cannot be turned into an epoch-day int for Flink's DateType, so the converter throws with the object class/value in the message.

Source

Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/formats/avro/AvroToRowDataConverters.java:267

        return TimestampData.fromEpochMillis(jodaConverter.convertTimestamp(object));
      } else {
        throw new IllegalArgumentException(
            "Unexpected object type for TIMESTAMP logical type. Received: " + object);
      }
    }
  }

  private static int convertToDate(Object object) {
    if (object instanceof Integer) {
      return (Integer) object;
    } else if (object instanceof LocalDate) {
      return (int) ((LocalDate) object).toEpochDay();
    } else {
      JodaConverter jodaConverter = JodaConverter.getConverter();
      if (jodaConverter != null) {
        return (int) jodaConverter.convertDate(object);
      } else {
        throw new IllegalArgumentException(
            "Unexpected object type for DATE logical type. Received: " + object);
      }
    }
  }

  private static int convertToTime(Object object) {
    final int millis;
    if (object instanceof Integer) {
      millis = (Integer) object;
    } else if (object instanceof LocalTime) {
      millis = ((LocalTime) object).get(ChronoField.MILLI_OF_DAY);
    } else {
      JodaConverter jodaConverter = JodaConverter.getConverter();
      if (jodaConverter != null) {
        millis = jodaConverter.convertTime(object);
      } else {
        throw new IllegalArgumentException(
            "Unexpected object type for TIME logical type. Received: " + object);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure the Avro reader maps the 'date' logical type to java.time.LocalDate (use Conversions or an up-to-date specific record)
  2. Add joda-time to the classpath if the source data uses legacy Joda date objects
  3. Pre-convert the field to LocalDate before feeding the record into the Flink Avro reader
  4. Align reader/writer schemas so the date logical type is declared in the schema

Example fix

// before: date field deserialized as String
// after: normalize before conversion
LocalDate d = LocalDate.parse((String) obj);
Defensive patterns

Strategy: type-guard

Validate before calling

Object d = record.get("date");
if (!(d instanceof LocalDate)) {
  d = LocalDate.parse(d.toString());
  record.put("date", d);
}

Type guard

boolean isLocalDate(Object o) {
  return o instanceof LocalDate;
}

Try / catch

try {
  RowData row = converter.convert(record);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("Unexpected object type for DATE")) {
    // convert field manually and retry
  } else { throw e; }
}

Prevention

When it happens

Trigger: Reading Avro data where a date field materializes as java.util.Date, String, or Integer instead of LocalDate, and JodaConverter is unavailable (no joda-time on classpath) or also cannot convert the type.

Common situations: Avro files written with reflect/generic records mapping 'date' to a non-LocalDate type; mixing java.time and Joda conventions across writer/reader versions.

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/52c855828602633a. Report an issue: GitHub.