apache/iceberg · error · IllegalArgumentException
Unexpected object type for TIMESTAMP logical type. Received:
Error message
Unexpected object type for TIMESTAMP logical type. Received: ${object} What it means
convertToTimestamp converts an Avro field value for a TIMESTAMP logical type into Flink TimestampData. It accepts LocalDateTime, java.util.Date/Instant via Joda bridge, etc.; when the object is none of the expected classes (and no Joda converter is available) it throws IllegalArgumentException reporting the actual object's toString.
Source
Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/formats/avro/AvroToRowDataConverters.java:251
return TimestampData.fromEpochMillis(timeLong);
} else if (precision <= 6) {
return TimestampData.fromEpochMillis(
Math.floorDiv(timeLong, 1000L), (int) Math.floorMod(timeLong, 1000L) * 1000);
} else {
// Iceberg: Added support for nanoseconds precision (FLINK-39251)
return TimestampData.fromEpochMillis(
Math.floorDiv(timeLong, 1_000_000L), (int) Math.floorMod(timeLong, 1_000_000L));
}
} else if (object instanceof Instant) {
return TimestampData.fromInstant((Instant) object);
} else if (object instanceof LocalDateTime) {
return TimestampData.fromLocalDateTime((LocalDateTime) object);
} else {
JodaConverter jodaConverter = JodaConverter.getConverter();
if (jodaConverter != null) {
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);
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Align the table's avro timestamp-mapping property with how the data files were actually written (rewrite files with the Spark/Avro rewrite procedure if mismatched).
- Check the 'Received:' value in the message to identify the actual Java class and adjust the reader/converter for that class.
- Upgrade or downgrade the iceberg-flink version so the converter matches the file's logical-type encoding (FLINK-39251 nanosecond support changed expectations).
- Pre-convert the field: wrap the raw object into LocalDateTime before it reaches the Avro→RowData converter (custom converter via createConverter overloads).
Example fix
// before
Object avroValue = record.get("ts"); // java.time.Instant (not LocalDateTime)
RowData row = converter.convert(record); // throws
// after
record.put("ts", LocalDateTime.ofInstant((Instant) avroValue, ZoneOffset.UTC));
RowData row = converter.convert(record); Defensive patterns
Strategy: validation
Validate before calling
Object v = record.get("ts");
if (!(v instanceof LocalDateTime) && !jodaSupported(v)) { throw new IllegalArgumentException("ts has unexpected class: " + v.getClass()); } Type guard
boolean isSupportedTimestamp(Object v) { return v instanceof LocalDateTime || v instanceof org.joda.time.DateTime || v instanceof java.util.Date; } Try / catch
try { return convertToTimestamp(obj, type); } catch (IllegalArgumentException e) { return TimestampData.fromLocalDateTime(toLocalDateTime(obj)); } Prevention
- Keep the avro timestamp-mapping property consistent with how files were written
- Rewrite files after changing timestamp mapping properties
- Ensure joda-time is on the classpath when reading legacy files
- Verify the actual class of timestamp values in Avro files when upgrading readers
When it happens
Trigger: Avro record contains a value under a timestamp logical-type field whose Java class is neither LocalDateTime nor a type handled by JodaConverter — typically a Long in legacy micros read with non-legacy converter expectations, or vice versa.
Common situations: Mismatch between the table's avro timestamp mapping property and the actual Avro file contents (files written with legacy Long encoding read via the modern converter); schema evolution changing field encoding without rewriting files.
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
- Unexpected object type for TIMESTAMP logical type. Received:
- Unexpected object type for TIMESTAMP logical type. Received:
- Unexpected object type for TIMESTAMP logical type. Received:
- Unknown type for long field. Type name: ${className}
- Unknown type for timestamp_ns: ${class}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/2980bb1fab2e788f.
Report an issue: GitHub.